Skip to main content

Full text of "Javascript Bible"

See other formats


J 




r CD-ROM Included! 
• 29 bonus chapter? 
• Wll" reddiy4c**ru n scripts 
* 10 real-world JavaScript applications 

Danny Goodman, M ichael Morrison, Paul Nov its 

Tia Gustaff R 



ava Scrip 




eveiith Edition 





c your web site 



ractive 

e dynamic content 
today s browsers 

ister Document 
ijcct Model concepts 





,j ^rvrfX •■ 



The book you need to succeed! 



Praise for Javascript® Bible 

"JavaScript® Bible is the definitive resource in JavaScript programming. I am never more than three 
feet from my copy." 

— Steve Reich, CEO, PageCoders 

"This book is a must-have for any web developer or programmer." 

— Thoma Lile, President, Kanis Technologies, Inc. 

"Outstanding book. I would recommend this book to anyone interested in learning to develop 
advanced Web sites. Mr. Goodman did an excellent job of organizing this book and writing it so that 
even a beginning programmer can understand it." 

— Jason Hensley, Director of Internet Services, NetVoice, Inc. 

"Goodman is always great at delivering clear and concise technical books!" 

— Dwayne King, Chief Technology Officer, White Horse 

"JavaScript® Bible is well worth the money spent!" 

— Yen C.Y. Leong, IT Director, Moo Mooltimedia, a member of SmartTransact Group 

"A must-have book for any internet developer." 

— Uri Fremder, Senior Consultant, TopTier Software 

"I love this book! I use it all the time, and it always delivers. It's the only JavaScript book I use!" 

— Jason Badger, Web Developer 

"Whether you are a professional or a beginner, this is a great book to get." 

— Brant Mutch, Web Application Developer, Wells Fargo Card Services, Inc. 

"I never thought I'd ever teach programming before reading your book [JavaScript® Bible] . It's so 
simple to use — the Programming Fundamentals section brought it all back! Thank you for such a 
wonderful book, and for breaking through my programming block!" 

— Susan Sann Mahon, Certified Lotus Instructor, TechNet Training 

"Danny Goodman is very good at leading the reader into the subject. JavaScript® Bible has everything 
we could possibly need." 

— Philip Gurdon 

"An excellent book that builds solidly from whatever level the reader is at. A book that is both witty 
and educational." 

— Dave Vane 

"I continue to use the book on a daily basis and would be lost without it." 

— Mike Warner, Founder, Oak Place Productions 

"JavaScript® Bible is by far the best JavaScript resource I've ever seen (and I've seen quite a few)." 

— Robert J. Mirro, Independent Consultant, RJM Consulting 



JavaScript® Bible 

Seventh Edition 



JavaScript® Bible 

Seventh Edition 



Danny Goodman 
Michael Morrison 

Paul Novitski 
Tia Gustaff Rayl 




WILEY 

Wiley Publishing, Inc. 



JavaScript® Bible, Seventh Edition 



Published by 
Wiley Publishing, Inc. 
10475 Crosspoint Boulevard 
Indianapolis, IN 46256 
www . wi 1 ey . com 

Copyright © 2010 by Wiley Publishing, Inc., Indianapolis, Indiana 

Published simultaneously in Canada 

ISBN: 978-0-470-52691-0 

Manufactured in the United States of America 

10 987654321 

No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any 
means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 
107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, 
or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood 
Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should 
be addressed to the Permissions Department, John Wiley & Sons, Inc., Ill River Street, Hoboken, NJ 07030, (201) 
748-6011, fax (201) 748-6008, or online at http : / / www .wiley. com/go/permissions. 

Limit of Liability/Disclaimer of Warranty: The publisher and the author make no representations or warranties 
with respect to the accuracy or completeness of the contents of this work and specifically disclaim all warranties, 
including without limitation warranties of fitness for a particular purpose. No warranty may be created or extended 
by sales or promotional materials. The advice and strategies contained herein may not be suitable for every situation. 
This work is sold with the understanding that the publisher is not engaged in rendering legal, accounting, or other 
professional services. If professional assistance is required, the services of a competent professional person should be 
sought. Neither the publisher nor the author shall be liable for damages arising herefrom. The fact that an organiza- 
tion or web site is referred to in this work as a citation and/or a potential source of further information does not mean 
that the author or the publisher endorses the information the organization or web site may provide or recommenda- 
tions it may make. Further, readers should be aware that Internet web sites listed in this work may have changed or 
disappeared between when this work was written and when it is read. 

For general information on our other products and services please contact our Customer Care Department within the 
United States at (877) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. 

Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be avail- 
able in electronic books. 

Library of Congress Control Number: 2010923547 

Trademarks: Wiley and the Wiley logo are trademarks or registered trademarks of John Wiley & Sons, Inc. and/or 
its affiliates, in the United States and other countries, and may not be used without written permission. JavaScript is 
a registered trademark of Oracle America, Inc. All other trademarks are the property of their respective owners. Wiley 
Publishing, Inc. is not associated with any product or vendor mentioned in this book. 



To Tanya, with whom I share this loving orbit with Briar and Callum in our own 

cozy Klemperer rosette. 
— Paul Novitski 

To my husband, Edward, whose love, support, and encouragement kept me going 
through this and all my adventures, and to the memory of my parents who inspired 

me to step out in faith. 
— Tia Gustaff Rayl 



About the Authors 



Danny Goodman is the author of numerous critically acclaimed and best-selling books, including The 
Complete HyperCard Handbook, Danny Goodman's AppleScript Handbook, Dynamic HTML: The Definitive 
Reference, and JavaScript & DHTML Cookbook. He is a renowned authority on and expert teacher of 
computer scripting languages. His writing style and pedagogy continue to earn praise from readers 
and teachers around the world. 

Michael Morrison is a writer, developer, toy inventor, and author of a variety of books covering 
topics such as Java, C++, Web scripting, XML, game development, and mobile devices. Some of 
Michael's notable writing projects include Faster Smarter HTML and XML, Teach Yourself HTML 
& CSS in 24 Hours, and Beginning Game Programming. Michael is also the founder of Stalefish 
Labs (www.stalefishlabs.com), an entertainment company specializing in unusual games, toys, and 
interactive products. 

Paul Novitski has been writing software as a freelance programmer since 1981. He once taught 
himself BASIC in order to write a machine language disassembler so that he could lovingly hack 
Wang's OIS microcode. He has focused on internet programming since the late '90s. His company, 
Juniper Webcraft, produces HTML-strict websites featuring accessible, semantic markup, separation 
of development layers, and intuitive user interfaces. He knows the righteousness of elegant code, the 
poignancy of living on the bleeding edge of wilderness, the sweet melancholy of mbira music, and the 
scorching joy of raising twin boys. 

Tia Gustaff Rayl is a consultant who does development and training in database and Web 
technologies. Most recently she has published courseware for XHTML, CSS, JavaScript, and SQL. 
It comes as no surprise to those who know her that she began her software career with degrees in 
English and Education from the University of Florida. As is usual for most newcomers to the field, 
her introduction to computing was maintaining software. She went on to a long-standing career 
in the software industry in full life cycle system, application, and database development; project 
management; and training for PC and mainframe environments. In the mid-nineties she worked on 
early Web-enabled database applications, adding JavaScript to her repertoire. She continues to take on 
development projects to maintain her code-slinging skills. If she had any spare time (and money) she 
would go on an around-the-world cruise with her husband and two dogs. 



About the Technical Editor 

Benjamin Schupak holds a master's degree in computer science and has more than 11 years of pro- 
fessional programming experience for large corporations and U.S. federal departments. He lives in the 
New York metro area and enjoys traveling. 



Credits 



Executive Editor 

Carol Long 

Project Editor 

John Sleeva 

Technical Editor 

Benjamin Schupack 

Production Editor 

Rebecca Anderson 

Editorial Director 

Robyn B. Siesky 

Editorial Manager 

Mary Beth Wakefield 

Marketing Manager 

Ashley Zurcher 

Production Manager 

Tim Tate 

Vice President and Executive Group 
Publisher 

Richard Swadley 



Vice President and Executive Publisher 

Barry Pruett 

Associate Publisher 

Jim Minatel 

Project Coordinator, Cover 

Lynsey Stanford 

Proofreaders 

Maraya Cornell, Word One New York 
Sheilah Ledwidge, Word One New York 

Indexer 

Robert Swanson 

Cover Designer 

Michael E. Trent 

Cover Image 

© Joyce Haughey 



My gratitude for being given the opportunity and the latitude to work on this immense tome 
extends to Carol Long of Wiley, editor John Sleeva, Carole Jelen at Waterside Productions, Julian 
Hall, my partner in crime at Juniper Webcraft, and, above all, my sweet, loving, supportive, 
and nearly homicidal spouse Tanya Wright, all of them long-suffering and all to be commended 
for not actually throttling me in the course of this overlong birthing. The solid foundation of 
research and explication established by Danny Goodman and his past collaborators in previous 
editions is awesome and I am humbled to have been able to help move this great body of knowledge 
forward to the next step. Tia Gustaff Rayl, who with wings spread and sparks flying rode in to the 
rescue, has been a kick in the pants to work with; she's smart and funny, but more than that she is 
gifted with the precise serendipity and good taste to share a birthday with me. 

-Paul Novitski 

I have been blessed with the support of many people who have reviewed my work and encouraged 
me along the way. I could never have done any of this without the devoted support of my husband, 
Edward. I love him without cease and thank God for bringing him into my life. I have been blessed by 
the remarkable patience of an incredibly tolerant immediate and extended family, as well as amused 
friends, who put up with my "Hi, I love you. Don't talk to me right now." way of answering the phone 
and greeting visitors at the door. My husband, family and friends are the ones who sacrificed the most 
for this book. Thank you all. I want to thank Paul for being great to work with and for his wry sense 
of humor which left me on the floor laughing just when I most needed a lift. I want to thank my edi- 
tor, John Sleeva, who with great patience and humor guided me through the maze of the publishing 
world. I also want to thank Rebecca Anderson and Maraya Cornell for forcing me to be a better writer. 
Finally, I want to thank Miss Bigelow, my 11th and 12th grade English teacher, who instilled within 
me a great respect and love for the written word. 

-Tia Gustaff Rayl 



xiii 




Introduction xxv 

Part I: Getting Started with JavaScript 1 

Chapter 1: JavaScript's Role in the World Wide Web and Beyond 3 

Chapter 2: Developing a Scripting Strategy 15 

Chapter 3: Selecting and Using Your Tools 27 

Chapter 4: JavaScript Essentials 37 

Part II: JavaScript Tutorial 59 

Chapter 5: Your First JavaScript Script 61 

Chapter 6: Browser and Document Objects 77 

Chapter 7: Scripts and HTML Documents 95 

Chapter 8: Programming Fundamentals, Part I 109 

Chapter 9: Programming Fundamentals, Part II 121 

Chapter 10: Window and Document Objects 135 

Chapter 11: Forms and Form Elements 153 

Chapter 12: Strings, Math, and Dates 179 

Chapter 13: Scripting Frames and Multiple Windows 191 

Chapter 14: Images and Dynamic HTML 207 

Part III: JavaScript Core Language Reference 223 

Chapter 15: The String Object 225 

Chapter 16: The Math, Number, and Boolean Objects 269 

Chapter 17: The Date Object 285 

Chapter 18: The Array Object 311 

Chapter 19: JSON — Native JavaScript Object Notation 357 

Chapter 20: E4X — Native XML Processing 363 

Chapter 21: Control Structures and Exception Handling 373 

Chapter 22: JavaScript Operators 411 

Chapter 23: Function Objects and Custom Objects 437 

Chapter 24: Global Functions and Statements 481 

Part IV: Document Objects Reference 501 

Chapter 25: Document Object Model Essentials 503 

Chapter 26: Generic HTML Element Objects 537 

Chapter 27: Window and Frame Objects 739 

Chapter 28: Location and History Objects 881 

Chapter 29: Document and Body Objects 907 

Chapter 30: Link and Anchor Objects 995 

Chapter 31: Image, Area, Map, and Canvas Objects 1003 

Chapter 32: Event Objects 1043 



XV 



Contents at a Glance 



Part V: Appendixes 1123 

Chapter A: JavaScript and Browser Objects Quick Reference 1125 

Chapter B: What's on the CD-ROM 1133 

Index 1137 

Bonus Chapters on the CD-ROM 

Part VI: Document Objects Reference (continued) BC1 

Chapter 33: Body Text Objects BC2 

Chapter 34: The Form and Related Objects BC103 

Chapter 35: Button Objects BC128 

Chapter 36: Text-Related Form Objects BC153 

Chapter 37: Select, Option, and FileUpload Objects BC177 

Chapter 38: Style Sheet and Style Objects BC207 

Chapter 39: Ajax, E4X, and XML BC272 

Chapter 40: HTML Directive Objects BC289 

Chapter 41: Table and List Objects BC303 

Chapter 42: The Navigator and Other Environment Objects BC360 

Chapter 43: Positioned Objects BC411 

Chapter 44: Embedded Objects BC448 

Chapter 45: The Regular Expression and RegExp Objects BC465 

Part VII: More JavaScript Programming BC491 

Chapter 46: Data-Entry Validation BC492 

Chapter 47: Scripting Java Applets and Plug-Ins BC524 

Chapter 48: Debugging Scripts BC564 

Chapter 49: Security and Netscape Signed Scripts BC590 

Chapter 50: Cross-Browser Dynamic HTML Issues BC608 

Chapter 51: Internet Explorer Behaviors BC623 

Part VIII: Applications BC636 

Chapter 52: Application: Tables and Calendars BC637 

Chapter 53: Application: A Lookup Table BC652 

Chapter 54: Application: A Poor Man's Order Form BC665 

Chapter 55: Application: Outline-Style Table of Contents BC674 

Chapter 56: Application: Calculations and Graphics BC695 

Chapter 57: Application: Intelligent "Updated" Flags BC705 

Chapter 58: Application: Decision Helper BC715 

Chapter 59: Application: Cross-Browser DHTML Map Puzzle BC747 

Chapter 60: Application: Transforming XML Data BC764 

Chapter 61: Application: Creating Custom Google Maps BC782 

Part IX: Appendixes (continued) BC799 

Appendix C: JavaScript Reserved Words BC800 

Appendix D: Answers to Tutorial Exercises BC801 

Appendix E: JavaScript and DOM Internet Resources BC818 




Introduction xxv 

Parti: Getting Started with JavaScript 1 



Chapter 1 : JavaScript's Role in the World Wide Web and Beyond 3 

Competing for Web Traffic 4 

Other Web Technologies 4 

JavaScript: A Language for All 10 

JavaScript: The Right Tool for the Right Job 12 

Chapter 2: Developing a Scripting Strategy 15 

Browser Leapfrog 15 

Duck and Cover 16 

Compatibility Issues Today 17 

Developing a Scripting Strategy 22 

Chapter 3: Selecting and Using Your Tools 27 

The Software Tools 27 

Setting Up Your Authoring Environment 28 

Validate, Validate, Validate 31 

Creating Your First Script 31 

Chapter 4: JavaScript Essentials 37 

Combining JavaScript with HTML 37 

Designing for Compatibility 51 

Language Essentials for Experienced Programmers 54 

Part II: JavaScript Tutorial 59 



Chapter 5: Your First JavaScript Script 61 

What Your First Script Will Do 61 

Entering Your First Script 62 

Have Some Fun 74 

Exercises 75 

Chapter 6: Browser and Document Objects 77 

Scripts Run the Show 77 

When to Use JavaScript 78 

The Document Object Model 79 

When a Document Loads 82 



xvii 



Contents 



Object References 85 

Node Terminology 87 

What Defines an Object? 88 

Exercises 93 

Chapter 7: Scripts and HTML Documents 95 

Connecting Scripts to Documents 95 

JavaScript Statements 99 

When Script Statements Execute 100 

Viewing Script Errors 104 

Scripting versus Programming 105 

Exercises 106 

Chapter 8: Programming Fundamentals, Part I 109 

What Language Is This? 109 

Working with Information 109 

Variables 110 

Expressions and Evaluation 112 

Data Type Conversions 115 

Operators 116 

Exercises 118 

Chapter 9: Programming Fundamentals, Part II 121 

Decisions and Loops 121 

Control Structures 122 

Repeat Loops 124 

Functions 124 

Curly Braces 128 

Arrays 129 

Exercises 133 

Chapter 10: Window and Document Objects 135 

Top-Level Objects 135 

The window Object 135 

window Properties and Methods 139 

The location Object 142 

The navigator Object 143 

The document Object 143 

Exercises 152 

Chapter 11: Forms and Form Elements 153 

The Form object 153 

Form Controls as Objects 158 

Passing Elements to Functions with this 170 

Submitting and Prevalidating Forms 173 

Exercises 177 

Chapter 12: Strings, Math, and Dates 179 

Core Language Objects 179 

String Objects 180 

The Math Object 183 

The Date Object 184 



xviii 



Contents 



Date Calculations 186 

Exercises 189 

Chapter 13: Scripting Frames and Multiple Windows 191 

Frames: Parents and Children 191 

Relerences Among Family Members 194 

Frame-Scripting Tips 195 

About iframe Elements 196 

Highlighting Footnotes: A Frameset Scripting Example 196 

References for Multiple Windows 202 

Exercises 206 

Chapter 14: Images and Dynamic HTML 207 

The Image Object 207 

Rollovers Without Scripts 216 

The javascript: Pseudo-URL 219 

Popular Dynamic HTML Techniques 220 

Exercises 222 

Part III: JavaScript Core Language Reference 223 



Chapter 15: The String Object 225 

String and Number Data Types 225 

String Object 228 

String Utility Functions 261 

URL String Encoding and Decoding 267 

Chapter 16: The Math, Number, and Boolean Objects 269 

Numbers in JavaScript 269 

Math Object 276 

Number Object 280 

Boolean Object 284 

Chapter 17: The Date Object 285 

Time Zones and GMT 285 

The Date Object 287 

Validating Date Entries in Forms 304 

Chapter 18: The Array Object 311 

Structured Data 311 

Creating an Empty Array 312 

Populating an Array 313 

JavaScript Array Creation Enhancements 314 

Deleting Array Entries 315 

Parallel Arrays 315 

Multidimensional Arrays 320 

Simulating a Hash Table 321 

Array Object 323 

Array Comprehensions 353 

xix 



Contents 



Destructuring Assignment 354 

Compatibility with Older Browsers 355 

Chapter 19: JSON - Native JavaScript Object Notation 357 

How JSON Works 357 

Sending and Receiving JSON Data 359 

JSON Object 360 

Security Concerns 361 

Chapter 20: E4X - Native XML Processing 363 

XML 363 

ECMAScript for XML (E4X) 364 

Chapter 21 : Control Structures and Exception Handling 373 

If and If. . .Else Decisions 373 

Conditional Expressions 379 

The switch Statement 380 

Repeat (for) Loops 384 

The while Loop 388 

The do-while Loop 390 

Looping through Properties (for-in) 390 

The with Statement 392 

Labeled Statements 393 

Exception Handling 397 

Using try-catch-finally Constructions 398 

Throwing Exceptions 402 

Error Object 407 

Chapter 22: JavaScript Operators 411 

Operator Categories 411 

Comparison Operators 412 

Equality of Disparate Data Types 413 

Connubial Operators 415 

Assignment Operators 418 

Boolean Operators 420 

Bitwise Operators 424 

Object Operators 425 

Miscellaneous Operators 430 

Operator Precedence 433 

Chapter 23: Function Objects and Custom Objects 437 

Function Object 437 

Function Application Notes 447 

Creating Your Own Objects with Object-Oriented JavaScript 458 

Object-Oriented Concepts 470 

Object Object 474 

Chapter 24: Global Functions and Statements 481 

Functions 482 

Statements 492 

WinlE Objects 496 



XX 



Contents 



Part IV: Document Objects Reference 501 



Chapter 25: Document Object Model Essentials 503 

The Object Model Hierarchy 503 

How Document Objects Are Born 505 

Object Properties 506 

Object Methods 507 

Object Event Handlers 508 

Object Model Smorgasbord 509 

Basic Object Model 510 

Basic Object Model Plus Images 511 

Navigator 4-Only Extensions 511 

Internet Explorer 44- Extensions 512 

Internet Explorer 54- Extensions 515 

The W3C DOM 516 

Scripting Trends 532 

Standards Compatibility Modes (DOCTYPE Switching) 534 

Where to Go from Here 535 

Chapter 26: Generic HTML Element Objects 537 

Generic Objects 537 

Chapter 27: Window and Frame Objects 739 

Window Terminology 739 

Frames 740 

window Object 746 

frame Element Object 854 

frameset Element Object 862 

iframe Element Object 868 

popup Object 875 

Chapter 28: Location and History Objects 881 

location Object 881 

history Object 900 

Chapter 29: Document and Body Objects 907 

document Object 908 

body Element Object 981 

TreeWalker Object 990 

Chapter 30: Link and Anchor Objects 995 

Anchor, Link, and a Element Objects 995 

Chapter 31: Image, Area, Map, and Canvas Objects 1003 

Image and img Element Objects 1003 

area Element Object 1024 

map Element Object 1028 

canvas Element Object 1032 

xxi 



Contents 



Chapter 32: Event Objects 1043 

Why "Events"? 1044 

Event Propagation 1045 

Referencing the event Object 1059 

Binding Events 1059 

event Object Compatibility 1064 

Dueling Event Models 1066 

Event Types 1070 

NN64-/Moz event Object 1097 

PartV: Appendixes 1123 

Appendix A: JavaScript and Browser Objects Quick Reference 1125 

Appendix B: What's on the CD-ROM 1133 

Index 1137 

Bonus Chapters on the CD-ROM 

Part VI: Document Objects Reference (continued) BC1 

Chapter 33: Body Text Objects BC2 

Chapter 34: The Form and Related Objects BC103 

Chapter 35: Button Objects BC128 

Chapter 36: Text-Related Form Objects BC153 

Chapter 37: Select, Option, and FileUpload Objects BC177 

Chapter 38: Style Sheet and Style Objects BC207 

Chapter 39: Ajax, E4X, and XML BC272 

Chapter 40: HTML Directive Objects BC289 

Chapter 41 : Table and List Objects BC303 

Chapter 42: The Navigator and Other Environment Objects BC360 

Chapter 43: Positioned Objects BC411 

xxii 



Contents 



Chapter 44: Embedded Objects BC448 

Chapter 45: The Regular Expression and RegExp Objects BC465 

Part VII: More JavaScript Programming BC491 

Chapter 46: Data-Entry Validation BC492 

Chapter 47: Scripting Java Applets and Plug-Ins BC524 

Chapter 48: Debugging Scripts BC564 

Chapter 49: Security and Netscape Signed Scripts BC590 

Chapter 50: Cross-Browser Dynamic HTML Issues BC608 

Chapter 51: Internet Explorer Behaviors BC623 

Part VIII: Applications BC636 

Chapter 52: Application: Tables and Calendars BC637 

Chapter 53: Application: A Lookup Table BC652 

Chapter 54: Application: A Poor Man's Order Form BC665 

Chapter 55: Application: Outline-Style Table of Contents BC674 

Chapter 56: Application: Calculations and Graphics BC695 

Chapter 57: Application: Intelligent "Updated" Flags BC705 

Chapter 58: Application: Decision Helper BC715 

Chapter 59: Application: Cross-Browser DHTML Map Puzzle BC747 

Chapter 60: Application: Transforming XML Data BC764 

Chapter 61: Application: Creating Custom Google Maps BC782 

Part IX: Appendixes (continued) BC799 

Appendix C: JavaScript Reserved Words BC800 

Appendix D: Answers to Tutorial Exercises BC801 

Appendix E: JavaScript and DOM Internet Resources BC818 



xxiii 




his seventh edition of the JavaScript Bible represents knowledge and experience accumulated 
over fifteen years of daily work in JavaScript and a constant monitoring of newsgroups for 
questions, problems, and challenges facing scripters at all levels. Our goal is to help you avoid 



the same frustration and head-scratching we and others have experienced through multiple genera- 
tions of scrip table browsers. 

While the earliest editions of this book focused on the then-predominant Netscape Navigator browser, 
the browser market share landscape has changed through the years. For many years, Microsoft took a 
strong lead with its Internet Explorer, but more recently, other browsers that support industry stan- 
dards are finding homes on users' computers. The situation still leaves an age-old dilemma for content 
developers: designing scripted content that functions equally well in both standards-compliant and 
proprietary environments. The job of a book claiming to be the "bible" is not only to present both 
the standard and proprietary details when they diverge, but also to show you how to write scripts 
that blend the two so that they work on the wide array of browsers visiting your sites or web applica- 
tions. Empowering you to design and write good scripts is our passion, regardless of browser. It's true 
that our bias is toward industry standards, but not to the exclusion of proprietary features that may 
be necessary to get your content and scripting ideas flowing equally well on today's and tomorrow's 
browsers. 



Organization and Features of This Edition 

Like the previous three editions of the JavaScript Bible, this seventh edition contains far more infor- 
mation than can be printed and bound into a single volume. The complete contents can be found in 
the electronic version of this book (in PDF form) on the CD-ROM that accompanies the book. This 
edition is structured in such a way as to supply the most commonly needed information in its entirety 
in the printed portion of the book. Content that you use to learn the fundamentals of JavaScript and 
reference frequently are at your fingertips in the printed version, while chapters with more advanced 
content are in the searchable electronic version on the CD-ROM. Here are some details about the 
book's structure. 



Part I: Getting Started with JavaScript 

Part I of the book begins with a chapter that shows how JavaScript compares with Java and discusses 
its role within the rest of the World Wide Web. The web browser and scripting world have 
undergone significant changes since JavaScript first arrived on the scene. That's why Chapter 2 is 
devoted to addressing challenges facing scripters who must develop applications for both single- and 
cross-platform browser audiences amid rapidly changing standards efforts. Chapter 3 introduces some 
tools you can use to compose your pages and scripts, while Chapter 4 delves into the nitty-gritty of 
how to use JavaScript to run in a wide variety of browsers. 



XXV 



Introduction 



Part II: JavaScript Tutorial 

All of Part II is handed over to a tutorial for newcomers to JavaScript. Ten lessons provide you with 
a gradual path through browser internals, basic programming skills, and genuine browser scripting, 
with an emphasis on industry standards as supported by most of the scriptable browsers in use today. 
Exercises follow at the end of each lesson to help reinforce what you just learned and challenge you to 
use your new knowledge (you'll find answers to the exercises in Appendix D, on the CD-ROM). The 
goal of the tutorial is to equip you with sufficient experience to start scripting simple pages right away 
while making it easier for you to understand the in-depth discussions and examples in the rest of the 
book. 

Part III: JavaScript Core Language Reference 

Reference information for the core JavaScript language fills Part III. In all reference chapters, a compat- 
ibility chart indicates the browser version that supports each object and object feature. Guide words 
near the tops of pages help you find a particular term quickly. 

Part IV: Document Objects Reference 

Part IV, the largest section of the book, provides in-depth coverage of the document object models as 
implemented in today's browsers, including the object used for modern Ajax applications. As with the 
core JavaScript reference chapters of Part III, these DOM chapters display browser compatibility charts 
for every object and object feature. One chapter in particular, Chapter 26, contains reference material 
that is shared by most of the remaining chapters of Part IV. To help you refer back to Chapter 26 
from other chapters, a shaded tab along the outside edge of the page shows you at a glance where 
the chapter is located. Additional navigation aids include guide words near the tops of most pages to 
indicate which object and object feature is covered on the page. Note that the Objects Reference begun 
in Part IV of the book continues in Part VI on the CD, with an additional 13 chapters of reference 
material. 

Part V: Appendixes 

Appendix A offers a JavaScript and Browser Objects Quick Reference. Appendix B provides informa- 
tion about using the CD-ROM that comes with this book, which includes numerous bonus chapters 
and examples. 

Part VI: Document Objects Reference (continued) 

Beginning the portion of the book that resides only the accompanying CD, Part VI continues the doc- 
ument objects reference discussions that begin in Part IV by providing an additional 13 chapters of 
reference material. 

Part VII: More JavaScript Programming 

Chapters 46-51 discuss advanced JavaScript programming techniques, including data-entry validation, 
debugging, and security issues. 

Part VIII: Applications 

The final ten chapters of the book, available only on the CD-ROM, feature sample applications that 
cover the gamut from calendars to puzzles. 



xxvi 



Introduction 



Part IX: Appendixes (continued) 

The final three appendixes provide helpful reference information. These resources include a list of 
JavaScript reserved words in Appendix C, answers to Part II's tutorial exercises in Appendix D, and 
Internet resources in Appendix E. 

CD-ROM 

The CD-ROM is a gold mine of information. It begins with a PDF version of the entire contents of this 
seventh edition of the JavaScript Bible. This version includes bonus chapters covering: 

• Dynamic HTML, data validation, plug-ins, and security 

• Techniques for developing and debugging professional web-based applications 

• Ten full-fledged JavaScript real- world applications 

Another treasure trove on the CD-ROM is the Listings folder where you'll find over 300 
ready-to-run HTML documents that serve as examples of most of the document object model and 
JavaScript vocabulary words in Parts III and IV. All of the bonus chapter example listings are also 
included. You can run these examples with your JavaScript-enabled browser, but be sure to use the 
index.html page in the Listings folder as a gateway to running the listings. We could have provided 
you with humorous little sample code fragments out of context, but we think that seeing full-fledged 
HTML documents (simple though they may be) for employing these concepts is important. We 
encourage you to manually type the script listings from the tutorial (Part II) of this book. We believe 
you leam a lot, even by aping listings from the book, as you get used to the rhythms of typing scripts 
in documents. 

Be sure to check out the Chapter 4 listing file called evaluator.html. Many segments of Parts III 
and IV invite you to try out an object model or language feature with the help of an interactive work- 
bench, called The Evaluator — a JavaScript Bible exclusive! You see instant results and will quickly 
learn how the feature works. 

The Quick Reference from Appendix A is in PDF format on the CD-ROM for you to print out and 
assemble as a handy reference, if desired. Adobe Reader is also included on the CD-ROM, in case you 
don't already have it. 



Prerequisites to Learning JavaScript 

Although this book doesn't demand that you have a great deal of programming experience behind 
you, the more web pages you've created with HTML, the easier you will find it to understand how 
JavaScript interacts with the familiar elements you normally place in your pages. Occasionally, you will 
need to modify HTML tags to take advantage of scripting. If you are familiar with those tags already, 
the JavaScript enhancements will be simple to digest. 

To learn JavaScript, you won't need to know server scripting or how to pass information from a form 
to a server. The focus here is on client-side scripting, which operates independently of the server after 
the JavaScript-enhanced HTML page is fully loaded into the browser. However, we strongly believe 
that a public web page should be operational in the absence of JavaScript, so any dynamic function- 
ality that looks up results or modifies the content of a page should interact with a server-side script 
fundamentally. After that foundation is laid, we add JavaScript to make a page faster, easier, or more 



xxvii 



Introduction 



fun. So although you don't need to know server-side scripting in order to leam JavaScript, for seri- 
ous web work you should either learn a server-side scripting language such as PHP in addition to 
JavaScript or look for server-side programmers to complement your client-side scripting abilities. 

The basic vocabulary of the current HTML standard should be part of your working knowledge. You 
should also be familiar with some of the latest document markup standards, such as XHTML and 
Cascading Style Sheets (CSS). Web searches for these terms will uncover numerous tutorials on the 
subjects. 

If you've never programmed before 

Don't be put off by the size of this book. JavaScript may not be the easiest language in the world to 
learn, but believe us, it's a far cry from having to learn a full programming language such as Java or C. 
Unlike developing a full-fledged monolithic application (such as the productivity programs you buy in 
stores), JavaScript lets you experiment by writing small snippets of program code to accomplish big 
things. The JavaScript interpreter built into every scriptable browser does a great deal of the technical 
work for you. 

Programming, at its most basic level, consists of nothing more than writing a series of instructions 
for the computer to follow. We humans follow instructions all the time, even if we don't realize it. 
Traveling to a friend's house is a sequence of small instructions: Go three blocks that way; turn left 
here; turn right there. Amid these instructions are some decisions that we have to make: If the stop- 
light is red, then stop; if the light is green, then go; if the light is yellow, then floor it! (Just kidding.) 
Occasionally, we must repeat some operations several times (kind of like having to go around the 
block until a parking space opens up). A computer program not only contains the main sequence of 
steps, but it also anticipates what decisions or repetitions may be needed to accomplish the program's 
goal (such as how to handle the various states of a stoplight or what to do if someone just stole the 
parking spot you were aiming for). 

The initial hurdle of learning to program is becoming comfortable with the way a programming lan- 
guage wants its words and numbers organized in these instructions. Such rules are called syntax, the 
same as in a living language. Computers aren't very forgiving if you don't communicate with them in 
the specific language they understand. When speaking to another human, you can flub a sentence's 
syntax and still have a good chance that the other person will understand you. Not so with computer 
programming languages. If the syntax isn't perfect (or at least within the language's range of knowl- 
edge), the computer has the brazenness to tell you that you have made a syntax error. 

The best thing you can do is just accept the syntax errors you receive as learning experiences. Even 
experienced programmers make mistakes. Every syntax error you get — and every resolution of that 
error made by rewriting the wayward statement — adds to your knowledge of the language. 

If you've done a little programming before 

Programming experience in a procedural language, such as BASIC, may actually be a hindrance rather 
than a help to learning JavaScript. Although you may have an appreciation for precision in syntax, the 
overall concept of how a program fits into the world is probably radically different from JavaScript's 
role. Part of this has to do with the typical tasks a script performs (carrying out a very specific task 
in response to user action within a web page), but a large part also has to do with the nature of 
object-oriented programming. 



xxviii 



Introduction 



If you've programmed in C before 

In a typical procedural program, the programmer is responsible for everything that appears on the 
screen and everything that happens under the hood. When the program first runs, a great deal of 
code is dedicated to setting up the visual environment. Perhaps the screen contains several text entry 
fields or clickable buttons. To determine which button a user clicks, the program examines the coordi- 
nates of the click and compares those coordinates against a list of all button coordinates on the screen. 
Program execution then branches out to perform the instructions reserved for clicking in that space. 

Object-oriented programming is almost the inverse of that process. A button is considered an 
object — something tangible. An object has properties, such as its label, size, alignment, and so on. 
An object may also contain a script. At the same time, the system software and browser, working 
together, can send a message to an object — depending on what the user does — to trigger the script. 
For example, if a user clicks in a text entry field, the system/browser tells the field that somebody has 
clicked there (that is, has set the focus to that field), giving the field the task of deciding what to do 
about it. That's where the script comes in. The script is connected to the field, and it contains the 
instructions that the field carries out after the user activates it. Another set of instructions may control 
what happens when the user types an entry and tabs or clicks out of the field, thereby changing the 
content of the field. 

Some of the scripts you write may seem to be procedural in construction: They contain a simple list 
of instructions that are carried out in order. But when dealing with data from form elements, these 
instructions work with the object-based nature of JavaScript. The form is an object; each radio button 
or text field is an object as well. The script then acts on the properties of those objects to get some 
work done. 

Making the transition from procedural to object-oriented programming may be the most difficult chal- 
lenge for you. But when the concept clicks — a long, pensive walk might help — so many light bulbs 
will go on inside your head that you'll think you might glow in the dark. From then on, object orien- 
tation will seem to be the only sensible way to program. 

By borrowing syntax from Java (which, in turn, is derived from C and C++), JavaScript shares many 
syntactical characteristics with C. Programmers familiar with C will feel right at home. Operator sym- 
bols, conditional structures, and repeat loops follow very much in the C tradition. You will be less 
concerned about data types in JavaScript than you are in C. In JavaScript, a variable is not restricted 
to any particular data type. 

With so much of JavaScript's syntax familiar to you, you will be able to concentrate on document 
object model concepts, which may be entirely new to you. You will still need a good grounding in 
HTML to put your expertise to work in JavaScript. 

If you've programmed in Java before 

Despite the similarity in their names, the two languages share only surface aspects: loop and 
conditional constructions, C-like "dot" object references, curly braces for grouping statements, several 
keywords, and a few other attributes. Variable declarations, however, are quite different, because 
JavaScript is a loosely typed language. A variable can contain an integer value in one statement and a 
string in the next (though we're not saying that this is good style). What Java refers to as methods, 
JavaScript calls methods (when associated with a predefined object) or functions (for scripter-defined 
actions). JavaScript methods and functions may return values of any type without having to state the 
data type ahead of time. 



xxix 



Introduction 



Perhaps the most important Java concepts to suppress when writing JavaScript are the object-oriented 
notions of classes, inheritance, instantiation, and message passing. These aspects are simply non-issues 
when scripting. At the same time, however, JavaScript's designers knew that you'd have some 
hard-to-break habits. For example, although JavaScript does not require a semicolon at the end 
of each statement line, if you type one in your JavaScript source code, the JavaScript interpreter 
won't balk. 

If you've written scripts (or macros) before 

Experience with writing scripts in other authoring tools or macros in productivity programs is help- 
ful for grasping a number of JavaScript's concepts. Perhaps the most important concept is the idea 
of combining a handful of statements to perform a specific task on some data. For example, you can 
write a macro in Microsoft Excel that performs a data transformation on daily figures that come in 
from a corporate financial report on another computer. The macro is built into the Macro menu, and 
you run it by choosing that menu item whenever a new set of figures arrives. 

Some modern programming environments, such as Visual Basic, resemble scripting environments in 
some ways. They present the programmer with an interface builder, which does most of the work of 
displaying screen objects with which the user will interact. A big part of the programmer's job is to 
write little bits of code that are executed when a user interacts with those objects. A great deal of the 
scripting you will do with JavaScript matches that pattern exactly. In fact, those environments resem- 
ble the scriptable browser environment in another way: They provide a finite set of predefined objects 
that have fixed sets of properties and behaviors. This predictability makes learning the entire environ- 
ment and planning an application easier to accomplish. 



Formatting and Naming Conventions 

The script listings and words in this book are presented in a monospace font to set them apart 
from the rest of the text. Because of restrictions in page width, lines of script listings may, from time 
to time, break unnaturally. In such cases, the remainder of the script appears in the following line, 
flush with the left margin of the listing, just as it would appear in a text editor with word wrapping 
turned on. If these line breaks cause you problems when you type a script listing into a document 
yourself, we encourage you to access the corresponding listing on the CD-ROM to see how it should 
look when you type it. 

As soon as you reach Part III of this book, you won't likely go for more than a page before reading 
about an object model or language feature that requires a specific minimum version of one browser 
or another. To make it easier to spot in the text when a particular browser and browser version is 
required, most browser references consist of an abbreviation and a version number. For example, 
WinIE5 means Internet Explorer 5 for Windows; NN4 means Netscape Navigator 4 for any operat- 
ing system; Moz stands for the modern Mozilla browser (from which Firefox, Netscape 6 or later, and 
Camino are derived); and Safari is Apple's own browser for Mac OS X. If a feature is introduced with 
a particular version of browser and is supported in subsequent versions, a plus symbol (4-) follows 
the number. For example, a feature marked WinIE5.54- indicates that Internet Explorer 5.5 for Win- 
dows is required at a minimum, but the feature is also available in WinIE8 and probably future WinlE 
versions. If a feature was implemented in the first release of a modern browser, a plus symbol imme- 
diately follows the browser family name, such as Moz4- for all Mozilla-based browsers. Occasionally, 
a feature or some highlighted behavior applies to only one browser. For example, a feature marked 



XXX 



Introduction 



NN4 means that it works only in Netscape Navigator 4.x. A minus sign (e.g., WmlE-) means that the 
browser does not support the item being discussed. 

The format of HTML markup in this edition follows HTML5 coding conventions, but also adheres to 
many XHTML standards such as all-lowercase tag and attribute names. 



Note Tip 
Caution Cross Reference 



Note, Tip, Caution, and Cross-Reference icons 
occasionally appear in the book to flag important 
points or suggest where to find more information. 



xxxi 



JavaScript® Bible 

Seventh Edition 



Part I 



Getting Started 
with JavaScript 



IN THIS PART 



Chapter 1 

JavaScript's Role in the World 
Wide Web and Beyond 

Chapter 2 

Developing a Scripting Strategy 
Chapter 3 

Selecting and Using Your Tools 

Chapter 4 

JavaScript Essentials 



CHAPTER 

T 

JavaScript's Role 
in the World Wide 
Web and Beyond 



Many of the technologies that make the World Wide Web possible 
have far exceeded their original goals. Envisioned at the outset as 
a medium for publishing static text and image content across a 
network, the Web is forever being probed, pushed, and pulled by content 
authors. By taking for granted so much of the "dirty work" of conveying the 
bits between server and client computers, content developers and programmers 
dream of exploiting that connection to generate new user experiences and 
practical applications. It's not uncommon for a developer community to 
take ownership of a technology and mold it to do new and exciting things. 
But with so many web technologies — especially browser programming 
with JavaScript — within reach of everyday folks, we have witnessed an 
unprecedented explosion in turning the World Wide Web from a bland 
publishing medium into a highly interactive, operating system-agnostic 
authoring platform. 

The JavaScript language, working in tandem with related browser features, is a 
web-enhancing technology. When employed on the client computer, the lan- 
guage can help turn a static page of content into an engaging, interactive, and 
intelligent experience. Applications can be as subtle as welcoming a site's visitor 
with the greeting "Good morning!" when it is morning in the client computer's 
time zone — even though it is dinnertime where the server is located. Or, appli- 
cations can be much more obvious, such as delivering the content of a slide show 
in a one-page download while JavaScript controls the sequence of hiding, show- 
ing, and "flying slide" transitions as we navigate through the presentation. 

Of course, JavaScript is not the only technology that can give life to drab web 
content. Therefore, it is important to understand where JavaScript fits within the 
array of standards, tools, and other technologies at your disposal. The alternative 
technologies described in this chapter are HTML, Cascading Style Sheets (CSS), 
server programs, and plug-ins. In most cases, JavaScript can work side by side 
with these other technologies, even though the hype can make them sound like 
one-stop shopping places for all your interactive needs. (That's rarely the case.) 
Finally, you learn about the origins of JavaScript and what role it plays in today's 
advanced web browsers. 



IN THIS CHAPTER 



How JavaScript blends with 
other web-authoring 
technologies 

The history of JavaScript 

What kinds of jobs you should 
and should not entrust 
to JavaScript 



3 



Part I: Getting Started with JavaScript 



Competing for Web Traffic 

Web page publishers revel in logging as many visits to their sites as possible. Regardless of the ques- 
tionable accuracy of web page hit counts, a site consistently logging 10,000 dubious hits per week is 
clearly far more popular than one with 1,000 dubious hits per week. Even if the precise number is 
unknown, relative popularity is a valuable measure. Another useful number is how many links from 
outside pages lead to a site. A popular site will have many other sites pointing to it — a key to earn- 
ing high visibility in web searches. 

Encouraging people to visit a site frequently is the Holy Grail of web publishing. Competition for 
viewers is enormous. Not only is the Web like a 50 million -channel television, but also, the Web 
competes for viewers' attention with all kinds of computer-generated information. That includes any- 
thing that appears onscreen as interactive multimedia. 

Users of entertainment programs, multimedia encyclopedias, and other colorful, engaging, and 
mouse-finger-numbing actions are accustomed to high-quality presentations. Frequently, these 
programs sport first-rate graphics, animation, live-action video, and synchronized sound. By contrast, 
the lowest-common-denominator web page has little in the way of razzle-dazzle. Even with the help 
of Dynamic HTML and style sheets, the layout of pictures and text is highly constrained compared 
with the kinds of desktop publishing documents you see all the time. Regardless of the quality of 
its content, an unscripted, vanilla HTML document is flat. At best, interaction is limited to whatever 
navigation the author offers in the way of hypertext links or forms whose filled-in content magically 
disappears into the web site's server. 



Other Web Technologies 

With so many ways to spice up web sites and pages, you can count on competitors for your site's 
visitors to do their darnedest to make their sites more engaging than yours. Unless you are the sole 
purveyor of information that is in high demand, you continually must devise ways to keep your visi- 
tors coming back and entice new ones. If you design for an intranet, your competition is the drive for 
improved productivity by colleagues who use the internal web sites for getting their jobs done. 

These are all excellent reasons why you should care about using one or more web technologies to raise 
your pages above the noise. Let's look at the major technologies you should know about. 

Figure 1-1 illustrates the components that make up a typical dynamic web site. The core is a dialog 
between the server (the web host) and the client (the browser); the client requests data and the server 
responds. The simplest model would consist of just the server, a document, and a browser, but in 
practice web sites use the other components shown here, and more. 

The process begins when the browser requests a page from the server. The server delivers static HTML 
pages directly from its hard drive; dynamic pages are generated on-the-fly by scripts executed in a lan- 
guage interpreter, such as PHP, but likewise delivered by the server to the client, usually in the form 
of HTML markup. For example, a server-side database can store the items of a catalog, and a PHP 
script can look up those data records and mark them up as HTML when requested by the browser. 

The downloaded page may contain the addresses of other components: style sheets, JavaScript files, 
images, and other assets. The browser requests each of these, in turn, from the server, combining them 
into the final rendering of the page. 

A JavaScript program is inert — just another hunk of downloaded bits — until it's received by the 
browser, which validates its syntax and compiles it, ready for execution when called upon by the 



4 



Chapter 1 : JavaScript's Role in the World Wide Web and Beyond 



HTML page or the human user. It's then part of the web page and confined to the client side of the 
sever-client dialog. JavaScript can make requests of servers, as we'll see later, but it cannot directly 
access anything outside of the page it's part of and the browser that's running it. 



FIGURE 1-1 



The components of a typical dynamic web site. 



server-side 
scripting 
(e.g., PHP) 




database 
(e.g., MySQL) 



marked-up content 
(HTML, XHTML, XML) 



style sheets 
(CSS) 



client-side 
scripting 
(e.g., JavaScript) 



images & objects 
(e.g., JPEG, Flash) 





the user 



Hypertext Markup Language (HTML and XHTML) 

As an outgrowth of SGML (Standard Generalized Markup Language), HTML brings structure to the 
content of a page. This structure gives us handles on the content in several important ways: 

• Markup transforms a sea of undifferentiated text into discrete parts, such as headlines, 
paragraphs, lists, data tables, images, and input controls. Structure augments the meaning 
of the content by establishing relationships between different parts: between headline and 
subhead; between items in a list; between divisions of the page such as header, footer, 

and content columns. The semantics of a page are important to every reader: visual browsers 
for the sighted, vocal and Braille browsers for the visually impaired, search engines, and other 
software that parses the page, looking for a comprehensible structure. 

• The browser transforms some marked-up structures into objects with particular behaviors. An 
image spills out rows of pixels in visually meaningful patterns. A form control accepts input 
from the user, while a button submits those form control values to the server. A hyperlink can 
load a new page into the browser window. These different types of objects would not be possi- 
ble without some form of markup. 



5 



Part I: Getting Started with JavaScript 



• The way a page is presented on screen, in Braille, or in speech, is determined by a style sheet 
that points to elements on the page and assigns appearance, emphasis, and other attributes. 
Every browser comes with a default style sheet that makes headlines, body text, hyperlinks, 
and form controls look a particular way. As web developers, we create our own style sheets to 
override the browser defaults and make our pages look the way we want. A style sheet tells the 
browser how to render the HTML page by referring to the document's markup elements and 
their attributes. 

• Most importantly for the topic at hand, HTML markup gives JavaScript ways to locate and oper- 
ate on portions of a page. A script can collect all the images in a gallery, or jump to a particular 
paragraph, because of the way the document is marked up. 

Clearly, HTML markup and the way we handle it are critical to a document's structure and meaning, 
its presentation, and its successful interaction with JavaScript. While all the details of how best to use 
HTML are outside the scope of this book, it's clear that you'll want to hone your markup skills while 
you're learning JavaScript. Even the best script in the world can fail if launched on faulty, sloppy, or 
unplanned markup. 

In the early years of web development, back before the turn of the century, in that medieval era now 
known as "the 90s," web designers didn't have much consciousness about markup semantics and 
accessibility. Pages were marked up in any way that would produce a desired visual presentation, 
relying on the default styling of the browser and without regard for the sensibility of the markup. A 
developer might choose an h4 tag simply in order to produce a certain size and style of font, regard- 
less of the document's outline structure, or use data table markup for non-tabular content, simply 
to force the page layout to align. Required spaces and faux spacer images were mashed into the real 
content merely to tweak the appearance of the page: how things looked took complete precedence 
over what things meant. Fortunately, today that perspective seems quaintly old-fashioned, but unfor- 
tunately, there are still thousands of people producing pages that way and millions of pages left over 
from that dark era, their finger bones clutching at our sleeves and urging us to join them in their mor- 
bid pastime. It is one goal of this book to encourage you to code like a modern, living mammal, and 
not like a fossil. 

Relegating HTML to the category of a tagging language does disservice not only to the effort that 
goes into fashioning a first-rate web page, but also to the way users interact with the pages. To 
our way of thinking, any collection of commands and other syntax that directs the way users 
interact with digital information is programming. With HTML, a web-page author controls the 
user experience with the content just as the engineers who program Microsoft Excel craft 
the way users interact with spreadsheet content and functions. 

Version 4.0 and later of the published HTML standards endeavor to define the purpose of HTML as 
assigning context to content, leaving the appearance to a separate standard for style sheets. In other 
words, it's not HTML's role to signify that some text is italic but rather to signify why we might choose 
to italicize it. For example, you would tag a chunk of text that conveys emphasis (via the <em> tag) 
or to mark its purpose (<span c 1 a s s = " title")) separately from the decision of how to format 
it with the style sheet. This separation between HTML markup and CSS presentation is an extremely 
powerful concept that makes the tweaking and redesign of web sites much faster than in the old days 
of inline styling and <font> tags. 

XHTML is a more recent adaptation of HTML that adheres to stylistic conventions established 
by the XML (extensible Markup Language) standard. No new tags come with XHTML, but 
it reinforces the notion of tagging to denote a document's structure and content. While for 
several years XHTML was seen as the next stage of evolution of HTML toward the holy grail 
of a universal XML markup for documents, that promise has failed to deliver, in part because 
Microsoft, with its enormous share of the browser market, has consistently declined to accom- 
modate XHTML served correctly as appl i cati on/xhtml +xml . Nearly all XHTML documents 



6 



Chapter 1 : JavaScript's Role in the World Wide Web and Beyond 



today are served as text/html, which means that browsers treat them as just more HTML 
"tag soup." Perhaps the only advantage gained by using XHTML markup is the stricter set of 
rules used by the W3C HTML Validator (http://validator.w3.org), which checks to 
make sure that all tags are closed in XHTML documents, but isn't so fussy with HTML with its 
looser definitions. 

For convincing arguments against the use of XHTML served as text/html, read "Sending 
XHTML as text/html Considered Harmful," by Ian Hickson (http://hixie.ch/advocacy 
/ xhtml ) and "Beware of XHTML," by David Hammond (http : / /www . webdevout . net 
/articles/beware-of-xhtml). 

More recently, HTML5 has been growing in the Petri dishes of the World Wide Web Consortium 
(W3C). While modern browsers have only just begun to implement some of its features, HTML5 is 
considered by many to offer a more promising future than the seemingly abandoned XHTML. HTML5 
offers an enriched vocabulary of markup tags compared to version 4, the better to align the markup 
language with the uses to which HTML is put in the real world. 

Because HTML 4.01 is the prevailing markup language for the web today, the HTML samples in this 
book are compatible with HTML 4.01, except for those that illustrate newer HTML5 elements such 
as canvas. With the proper DOCTYPE, the samples should validate as HTML5. They are easily con- 
vertible to XHTML 1.0 with a few simple transforms: change the DOCTYPE, add 1 ang attributes to the 
HTML element, and close empty elements such as i nput and link with />. It's our hope that this 
will make the samples useful to folks heading up either HTML or XHTML paths, and also make the 
book more future-friendly as HTML5 comes into its own. 

Cascading Style Sheets (CSS) 

Specifying the look and feel and speech of a web page is the job of Cascading Style Sheets (CSS). 
Given a document's structure as spelled out by its HTML markup, a style sheet defines the layout, 
colors, fonts, voices, and other visual and aural characteristics to present the content. Applying a dif- 
ferent set of CSS definitions to the same document can make it look and sound entirely different, even 
though the words and images are the same. 

(CSS 2.1 is the version of the W3C style sheet specification most widely supported by today's user 
agents. Aural style sheets that let us assign voices and other sounds to the markup of a web page are 
a module of the CSS 3 specification and, at this writing, are supported only by Opera and the FireVox 
extension to Firefox, although other browsers are sure to follow.) 

Mastery of the fine points of CSS takes time and experimentation, but the results are worth the effort. 
The days of using HTML tables and transparent "spacer" images to generate elaborate multicolumn 
layouts are very much on the wane. Every web developer should have a solid grounding in CSS. 

The learning curve for CSS can be steep because of the inconsistent support for its many features 
from one browser to the next. You can make your life much easier by triggering standards mode in the 
browser, whereby it adheres more closely to the W3C CSS specification. We recommend triggering 
standards mode by using a correct DOCTYPE at the top of your markup, such as one of these: 

HTML 4.01 Strict: 

<!D0CTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/REC-html40/strict.dtd"> 

HTML 5: 

<!D0CTYPE html > 



7 



Part I: Getting Started with JavaScript 



XHTML 1.0 Strict: 

<!D0CTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
" http : / /www .w3.org/TR/xhtmll/xhtmll-strict.dtd"> 

For a clear explanation of DOCTYPE switching, read Eric Meyer's essay "Picking a Rendering Mode" 
(http : //www .ericmeyeron ess. com /bonus /render -mode. html). 

Server-side programming 

Web sites that rely on database access, or change their content very frequently, incorporate program- 
ming on the server that generates the HTML output for browsers and/or processes forms that site 
visitors fill out on the page. Even submissions from a simple login or search form ultimately trigger 
some server process that sends the results to your browser. Server programming takes on many guises, 
the names of which you may recognize from your surfing through web development sites. PHP, ASP, 
.NET, JSP, and ColdFusion are among the most popular. Associated programming languages include 
Perl, Python, Java, C++, C#, Visual Basic, and even server-side JavaScript in some environments. 

Whatever language you use, the job definitely requires the web-page author to be in control of the 
server, including whatever back-end programs (such as databases) are needed to supply results or mas- 
sage the information coming from the user. Even with the new, server-based web site design tools 
available, server scripting is often a task that a content-oriented HTML author will need to hand off to 
a more experienced programmer. 

Client-side JavaScript is not a replacement for server-side scripting. Any web site that reacts 
dynamically to user actions or that saves data must be driven by server-side scripting, even 
if JavaScript is used in the browser to enhance the user's experience. The reasons are simple: 
First, JavaScript itself cannot write to files on the server. It can help the user make choices and 
prepare data for upload, but after that it can only hand off data to a sever-side script for database 
updating. Second, not all user agents run JavaScript. Screen readers, mobile devices, search 
engines, and browsers installed in certain corporate contexts are among those that don't invoke 
JavaScript, or that receive web pages with the JavaScript stripped out. Therefore, your web site 
should be fully functional with JavaScript turned off. Use JavaScript to make the browsing expe- 
rience faster, cooler, or more fun when it's present, but don't let your site be broken if JavaScript 
isn't running. 

As powerful and useful as server-side scripting can be, its speed of interaction with the user is limited 
by the speed of the Internet connection between server and user agent. Obviously, any process 
that results in updating data on the server must include some client-server dialog, but there are 
many aspects of user interaction that, with the help of JavaScript, can take place entirely within the 
browser — form validation and drag-&-drop are two examples — then update the server when the 
response-sensitive process is complete. 

One way that server programming and browser scripting work together is with what has become 
known as Ajax — Asynchronous JavaScript and XML. The "asynchronous" part runs in the browser, 
requesting XML data from, or posting data to, the server-side script entirely in the background. XML 
data returned by the server can then be examined by JavaScript in the browser to update portions of 
the web page. That's how many popular web-based email user interfaces work, as well as the drag- 
gable satellite-photo closeups of Google Maps (http://maps.google.com). 

Working together, server programming and browser scripting can make beautiful applications 
together. You'll want to write in a server-side language such as PHP, or team up with someone who 
does, to lay the foundations for the JavaScript-enhanced pages you'll be creating. 



8 



Chapter 1 : JavaScript's Role in the World Wide Web and Beyond 



Of helpers and plug-ins 

In the early days of the World Wide Web, a browser needed to present only a few kinds of data 
before a user's eyes. The power to render text (tagged with HTML) and images (in popular formats 
such as GIF and JPEG) was built into browsers intended for desktop operating systems. Not 
wanting to be limited by those data types, developers worked hard to extend browsers so that 
data in other formats could be rendered on the client computer. It was unlikely, however, that 
a browser would ever be built that could download and render, say, any of several sound- 
file formats. 

One way to solve the problem was to allow the browser, upon recognizing an incoming file of a par- 
ticular type, to launch a separate application on the client machine to render the content. As long 
as this helper application was installed on the client computer (and the association with the helper 
program was set in the browser's preferences), the browser would launch the program and send the 
incoming file to that program. Thus, you might have one helper application for a MIDI sound file and 
another for an animation file. 

Beginning with Netscape Navigator 2 in early 1996, software plug-ins for browsers enabled develop- 
ers to extend the capabilities of the browser without having to modify the browser. Unlike a helper 
application, a plug-in can enable external content to blend into the document seamlessly. 

The most common plug-ms are those that facilitate the playback of audio and video from the server. 
Audio may include music tracks that play in the background while visiting a page, or live (streaming) 
audio, similar to a radio station. Video and animation can operate in a space on the page when played 
through a plug-in that knows how to process such data. 

Today's browsers tend to ship with plug-ins that decode the most common sound-file types. Develop- 
ers of plug-ins for Internet Explorer for the Windows operating system commonly implement plug-ins 
as ActiveX controls — a distinction that is important to the underpinnings of the operating system, 
but not to the user. 

Plug-ins and helpers are valuable for more than just audio and video playback. A popular helper 
application is Adobe Acrobat Reader, which displays Acrobat files that are formatted just as though 
they were being printed. But for interactivity, developers today frequently rely on the Flash plug-in by 
Macromedia (now owned by Adobe). Created using the Flash authoring environment, a Flash applica- 
tion can have active clickable areas and draggable elements, animation, and embedded video. Some 
authors simulate artistic video games and animated stories in Flash. A browser equipped with the 
Flash plug-in displays the content in a rectangular area embedded within the browser page. A variant 
of JavaScript called ActionScript enables Flash to interact with the user and components of the HTML 
page. Like JavaScript, ActionScript gets access to outside resources by making data-read and -write 
requests of the server. YouTube.com is a popular example of a web site with richly integrated Flash. 

One potential downside for authoring interactive content in Flash or similar environments is that if 
the user does not have the correct plug-in version installed, it can take some time to download the 
plug-in (if the user even wants to bother). Moreover, once the plug-in is installed, highly graphic and 
interactive content can take longer to download to the client (especially on a dial-up connection) than 
some users are willing to wait. This is one of those situations in which you must balance your creative 
palette with the user's desire for your interactive content. 

Another client-side technology — the Java applet — was popular for a while in the late 1990s, but 
has fallen out of favor for a variety of reasons (some technical, some corporate-political). But this has 
not diminished the use of Java as a language for server and even cellular telephone programming, 
extending well beyond the scope of the language's founding company, Sun Microsystems. 



9 



Part I: Getting Started with JavaScript 



JavaScript: A Language for All 

Sun's Java language is derived from C and C++, but it is a distinct language. Its main audience is the 
experienced programmer. That leaves out many web-page authors. Java's preliminary specifications in 
1995 were dismaying. How much more preferable would have been a language that casual program- 
mers and scripters who were comfortable with authoring tools such as Apple's once-formidable Hyper- 
Card and Microsoft's Visual Basic could adopt quickly. As these accessible development platforms 
have shown, nonprofessional authors can dream up many creative applications, often for very specific 
tasks that no professional programmer would have the inclination to work on. Personal needs often 
drive development in the classroom, office, den, or garage. But Java was not going to be that kind of 
inclusive language. 

Spirits lifted several months later, in November 1995, when we heard of a scripting language 
project brewing at Netscape Communications, Inc. Bom under the name LiveScript, this language 
was developed in parallel with a new version of Netscape's web server software. The language was 
to serve two purposes with the same syntax. One purpose was as a scripting language that web 
server administrators could use to manage the server and connect its pages to other services, such as 
back-end databases and search engines for users looking up information. Extending the "Live" brand 
name further, Netscape assigned the name HveWire to the database connectivity usage of LiveScript 
on the server. 

On the client side — in HTML documents — authors could employ scripts written in this new 
language to enhance web pages in a number of ways. For example, an author could use LiveScript 
to make sure that the user had filled in a required text field with an e-mail address or credit 
card number. Instead of forcing the server or database to do the data validation (requiring data 
exchanges between the client browser and the server), the user's computer handles all the calculation 
work — putting some of that otherwise-wasted computing horsepower to work. In essence, LiveScript 
could provide HTML-level interaction for the user. 



LiveScript becomes JavaScript 

In early December 1995, just prior to the formal release of Navigator 2, Netscape and Sun Microsys- 
tems jointly announced that the scripting language thereafter would be known as JavaScript. Though 
Netscape had several good marketing reasons for adopting this name, the changeover may have con- 
tributed more confusion to both the Java programming world and HTML scripting world than anyone 
expected. 

Before the announcement, the language was already related to Java in some ways. Many of the basic 
syntax elements of the scripting language were reminiscent of the Java style. However, for client-side 
scripting, the language was intended for very different purposes than Java — essentially to function 
as a programming language integrated into HTML documents rather than as a language for writing 
applets that occupy a fixed rectangular area on the page (and that are oblivious to anything else on 
the page). Instead of Java's full-blown programming language vocabulary (and conceptually more 
difficult-to-learn object-oriented approach), JavaScript had a small vocabulary and a more easily 
digestible programming model. 

The true difficulty, it turned out, was making the distinction between Java and JavaScript clear to the 
world. Many computer journalists made major blunders when they said or implied that JavaScript pro- 
vided a simpler way of building Java applets. To this day, some new programmers believe JavaScript is 
synonymous with the Java language: They post Java queries to JavaScript-specific Internet newsgroups 
and mailing lists. 



10 



Chapter 1 : JavaScript's Role in the World Wide Web and Beyond 



The fact remains that client-side Java and JavaScript are more different than they are similar. The two 
languages employ entirely different interpreter engines to execute their code. 

Enter Microsoft and others 

Although the JavaScript language originated at Netscape, Microsoft acknowledged the potential power 
and popularity of the language by implementing it (under the JScript name) in Internet Explorer 3. 
Even if Microsoft might prefer that the world use the VBScript (Visual Basic Script) language that it 
provides in the Windows versions of IE, the fact that JavaScript is available on more browsers and 
operating systems makes it the client-side scripter's choice for anyone who must design for a broad 
range of users. 

With scripting firmly entrenched in the mainstream browsers from Microsoft and Netscape, newer 
browser makers automatically provided support for JavaScript. Therefore, you can count on 
fundamental scripting services in browsers such as Opera or the Apple Safari browser (the latter built 
upon an Open Source browser called KHTML). Not that all browsers work the same way in every 
detail — a significant challenge for client-side scripting that is addressed throughout this book. 

JavaScript versions 

The JavaScript language has its own numbering system, which is completely independent of the ver- 
sion numbers assigned to browsers. The Mozilla Foundation, successor to the Netscape browser devel- 
opment group that created the language, continues its role as the driving force behind the JavaScript 
version numbering system. 

The first version, logically enough, was JavaScript 1.0. This was the version implemented in Naviga- 
tor 2, and the first release of Internet Explorer 3. As the language evolved with succeeding browser 
versions, the JavaScript version number incremented in small steps. JavaScript 1.2 is the version that 
has been the most long lived and stable, currently supported by Internet Explorer 7. Mozilla-based 
browsers and others have inched forward with some new features in JavaScript 1.5 (Mozilla 1.0 and 
Safari), JavaScript 1.6 (Mozilla 1.8 browsers), and JavaScript 1.7 (Mozilla 1.8.1 and later). 

Each successive generation of JavaScript employs additional language features. For example, in 
JavaScript 1.0, arrays were not developed fully, causing scripted arrays not to track the number of 
items in the array. JavaScript 1 . 1 filled that hole by providing a constructor function for generating 
arrays and an inherent length property for any generated array. 

The JavaScript version implemented in a browser is not always a good predictor of core language fea- 
tures available for that browser. For example, although JavaScript 1.2 (as implemented by Netscape 
in Netscape Navigator 4) included broad support for regular expressions, not all of those features 
appeared in Microsoft's corresponding JScript implementation in Internet Explorer 4. By the same 
token, Microsoft implemented try -catch error handling in its JScript in Internet Explorer 5, but 
Netscape didn't include that feature until the Mozilla-based Netscape Navigator 6 implementation of 
JavaScript 1.5. Therefore, the language version number is an unreliable predictor in determining which 
language features are available for you to use. 

Core language standard: ECMAScript 

Although Netscape first developed the JavaScript language, Microsoft incorporated the language in 
Internet Explorer 3. Microsoft did not want to license the Java name from its trademark owner (Sun 
Microsystems), which is why the language became known in the Internet Explorer environment as 



11 



Part I: Getting Started with JavaScript 



JScript. Except for some very esoteric exceptions and the pace of newly introduced features, the two 
languages are essentially identical. The levels of compatibility between browser brands for a compara- 
ble generation are remarkably high for the core language (unlike the vast disparities in object model 
implementations discussed in Chapter 25, "Document Object Model Essentials"). 

As mentioned, standards efforts have been under way to create industry-wide recommendations for 
browser makers to follow (to make developers' lives easier). The core language was among the first 
components to achieve standard status. Through the European standards body called ECMA, a for- 
mal standard for the language was agreed to and published. The first specification for the language, 
dubbed ECMAScript by the standards group, was roughly the same as JavaScript 1.1 in Netscape Nav- 
igator 3. The standard (ECMA-262) defines how various data types are treated, how operators work, 
what a particular data-specific syntax looks like, and other language characteristics. A newer version 
(called version 3) added many enhancements to the core language (version 2 was just version 1 with 
errata fixed). 

The current version of the ECMAScript specification is known as ECMAScript, Fifth Edition, 
published online at www . ecma -i nterna ti onal .org. To quote the ECMA, "The Fifth Edition 
codifies de facto interpretations of the language specification that have become common among 
browser implementations and adds support for new features that have emerged since the publication 
of the Third Edition. Such features include accessor properties, reflective creation and inspection 
of objects, program control of property attributes, additional array manipulation functions, support 
for the JSON object encoding format, and a strict mode that provides enhanced error checking and 
program security." 

If you are a student of programming languages, you will find the document fascinating; if you simply 
want to script your pages, you might find the minutia mind-boggling. 

All mainstream browser developers have pledged to make their browsers compliant with the ECMA 
standard. The vast majority of the ECMAScript standard has appeared in Navigator since version 3 
and Internet Explorer since version 4, and as new features are added to the ECMA standard, they tend 
to find their way into newer browsers as well. The latest version of ECMAScript is version 5. The pre- 
vious edition, the 3rd, has been supported in all mainstream browsers for the past few years. 



Note 

Even as ECMAScript, Fifth Edition was in the works, The Mozilla Foundation and Microsoft were implementing 
comparable versions of JavaScript 2.0 and JScript, respectively. An extension to ECMAScript called E4X 
(ECMAScript for XML) was finalized in late 2005 and is implemented in browsers based on Mozilla 1.8.1 or 
later (for example, Firefox 2.0). The Adobe ActionScript 3 language, which is used in the development of Flash 
animations, fully supports E4X. E4X is a significant addition to JavaScript because it makes XML (Extensible 
Markup Language) a native data type within the syntax of the language, making the processing of data in 
XML format much easier. XML is the data format used by many data exchange processes, including Ajax (see 
Chapter 39). ■ 



JavaScript: The Right Tool 

for the Right Job 

Knowing how to match an authoring tool to a solution-building task is an important part of being 
a well-rounded web site author. A web designer who ignores JavaScript is akin to a plumber who 
bruises his knuckles by using pliers instead of the wrench from the bottom of the toolbox. 



12 



Chapter 1 : JavaScript's Role in the World Wide Web and Beyond 



By the same token, JavaScript won't fulfill every dream. The more you understand about JavaScript's 
intentions and limitations, the more likely you will be to turn to it immediately when it is the proper 
tool. In particular, look to JavaScript for the following kinds of solutions: 

• Getting your web page to respond or react directly to user interaction with form elements (input 
fields, text areas, buttons, radio buttons, checkboxes, selection lists) and hypertext links 

• Distributing small collections of database-like information and providing a friendly interface to 
that data 

• Controlling multiple-frame navigation, plug-ins, or Java applets based on user choices in the 
HTML document 

• Preprocessing data on the client before submission to a server 

• Changing content and styles in modem browsers dynamically and instantly, in response to user 
interaction 

• Requesting files from the server, and making read and write requests of server-side scripts 

At the same time, it is equally important to understand what JavaScript is not capable of doing. 
Scripters waste many hours looking for ways of carrying out tasks for which JavaScript was not 
designed. Most of the limitations are intentional, to protect visitors from invasions of privacy or 
unauthorized access to their desktop computers. Therefore, unless a visitor uses a modern browser 
and explicitly gives you permission to access protected parts of his or her computer, JavaScript cannot 
surreptitiously perform any of the following actions: 

• Setting or retrieving the browser's preferences settings, main window appearance features, 
action buttons, and printing capability 

• Launching an application on the client computer 

• Reading or writing files or directories on the client computer (with one exception: cookies) 

• Writing directly to files on the server 

• Capturing live data streams from the server for retransmission 

• Sending secret e-mails from web site visitors to you (although it can send data to a server-side 
script capable of sending email) 

Web site authors are constantly seeking tools that will make their sites engaging (if not cool) with the 
least amount of effort. This is particularly true when the task of creating a web site is in the hands 
of people more comfortable with writing, graphic design, and page layout than with hard-core pro- 
gramming. Not every webmaster has legions of experienced programmers on hand to whip up some 
special, custom enhancement for the site. Neither does every web author have control over the web 
server that physically houses the collection of HTML and graphics files. JavaScript brings program- 
ming power within reach of anyone familiar with HTML, even when the server is a black box at the 
other end of a telephone line. 



13 



CHAPTER 



Developing a 
Scripting Strategy 




If you are starting to learn JavaScript at this point in the history of scriptable 
browsers, you have both a distinct advantage and a disadvantage. The advan- 
tage is that you have the wonderful capabilities of mature browser offerings 
from Microsoft, The Mozilla Foundation (under brand names such as Firefox, 
Netscape, and Camino), Apple, and others at your bidding. The disadvantage is 
that you have not experienced the painful history of authoring for older browser 
versions that were buggy and at times incompatible with one another due to 
a lack of standards. You have yet to learn the anguish of carefully devising a 
scripted application for the browser version you use, only to have site visitors 
send you voluminous email messages about how the page triggers all kinds of 
script errors when run on a different browser brand, generation, or operating 
system platform. 

Welcome to the real world of scripting web pages with JavaScript. Several 
dynamics are at work to help make an author's life difficult if the audience for 
the application uses more than a single type of browser. This chapter introduces 
you to these challenges before you type your first word of JavaScript code. Our 
fear is that the subjects we raise may dissuade you from progressing further 
into JavaScript and its powers. But as developers ourselves — and some of 
us have been using JavaScript since the earliest days of its public prerelease 
availability — we dare not sugar-coat the issues facing scripters today. Instead, 
we want to make sure you have an appreciation for what lies ahead to assist you 
in learning the language. We believe that if you understand the big picture of 
the browser-scripting world as it stands today, you will find it easier to target 
JavaScript usage in your web application development and be successful at it. 



IN THIS CHAPTER 



How leapfrogging browser 
developments help and hurt 
web developers 

Separating the core JavaScript 
language from document 
objects 

The importance of developing 
a cross-browser strategy 



Browser Leapfrog 

Browser compatibility has been an issue for authors since the earliest days of the 
web gold rush — long before JavaScript. Despite the fact that browser developers 
and other interested parties voiced their opinions during formative stages of stan- 
dards development, HTML authors could not produce a document that appeared 



15 



Part I: Getting Started with JavaScript 



the same, pixel by pixel, on all client machines. It may have been one thing to establish a set of stan- 
dard tags for defining heading levels and line breaks, but it was rare for the actual rendering of con- 
tent inside those tags to look identical on different brands of browsers on different operating systems. 

Then, as the competitive world heated up — and web browser development transformed itself from a 
volunteer undertaking into profit-seeking businesses — creative people defined new features and new 
tags that helped authors develop more flexible and interesting-looking pages. As happens a lot in any 
computer-related industry, the pace of commercial development easily surpassed the studied progress 
of standards. A browser maker would build a new HTML feature into a browser and only then pro- 
pose that feature to the relevant standards body. Web authors were using these features (sometimes 
for prerelease browser versions) before the proposals were published for review. 

When the deployment of content depends almost entirely on an interpretive engine on the client com- 
puter receiving the data — the HTML engine in a browser, for example — authors face an immediate 
problem. Unlike a stand-alone computer program that can extend and even invent functionality and 
have it run on everyone's computer (at least for a given operating system), web content providers must 
rely on the functionality built into the browser. This led to questions such as, "If not all browsers 
coming to my site support a particular HTML feature, then should I apply newfangled HTML features 
for visitors only at the bleeding edge?" and "If I do deploy the new features, what do I do for those 
with older browsers?" 

Authors who developed pages in the earliest days of the Web wrestled with these questions for many 
HTML features that we today take for granted. Tables and frames come to mind. Eventually, the stan- 
dards caught up with the proposed HTML extensions — but not without a lot of author woe along 
the way. 

Despite the current dominance of the Microsoft Internet Explorer browser on the dominant Windows 
operating system, the number of browsers that people use is not shrinking. Several recent browsers, 
including the modern Netscape, Firefox, and Camino browsers, are based on an Open Source browser 
called Mozilla. The Macintosh operating system includes its own Apple -branded browser, Safari 
(released in 2003). And the independent Opera browser also has a home on some users' computers. 
All of these non-Microsoft browser makers obviously believe that they bring improvements to the 
world to justify their development — building better mousetraps, you might say. 



Duck and Cover 

Today's browser wars are fought on different battlegrounds than in the early days of the Web. 
The breadth and depth of established web standards have substantially fattened the browser 
applications — and the books developers read to exploit those standards for their content. On one 
hand, most developers clamor for deeper standards support in new browser versions. On the other 
hand, everyday users care little about standards. All they want is to have an enjoyable time finding the 
information they seek on the Web. Most users are slow to upgrade, holding out until their favorite 
sites start breaking in their ancient browsers. 

Industry standards don't necessarily make the web developer's job any easier. For one thing, the stan- 
dards are unevenly implemented across the latest browsers. Some browsers go further in their support 
than others. Then, there are occasional differences in interpretation of vague standards details. Some- 
times the standards don't provide any guidance in areas that are vital to content developers. At times, 
we are left to the whims of browser makers who fill the gaps with proprietary features in the hope 
that those features will become de facto standards. 



16 



Chapter 2: Developing a Scripting Strategy 



As happens in war, civilian casualties mount when the big guns start shooting. The browser battle 
lines shifted dramatically in only a few years. The huge market-share territory once under Netscape's 
command came under Microsoft's sway. More recently, however, concerns about privacy and security 
on the Windows platform have driven many users to seek less vulnerable browsers. Mozilla Firefox 
has so far been the biggest beneficiary in the search for alternatives. Although a fair amount of author- 
ing common ground exists between the latest versions of today's browsers, uneven implementation of 
the newest features causes the biggest problems for authors wishing to deploy on all browsers. Trying 
to define the common denominator may be the toughest part of the authoring job. 



Compatibility Issues Today 

Allow us to describe the current status of the compatibility situation among the top three browser 
families: Microsoft Internet Explorer, browsers based on Mozilla, and Apple Safari. The discussion in 
the next few sections intentionally does not get into specific scripting technology very deeply; some of 
you may know very little about programming at this point. In many chapters throughout this book, 
we offer scripting suggestions to accommodate a variety of browsers. 

Separating the core JavaScript language from document objects 

Although early JavaScript authors initially treated client-side scripting as one environment that permit- 
ted the programming of page elements, the scene has changed as the browsers have matured. Today, 
a clear distinction exists between specifications for the core JavaScript language and for the elements 
you script in a document — for example, buttons and fields in a form (see Figure 2-1). 



FIGURE 2-1 



The document object model is the programming interface between the HTML or XML document 
and the JavaScript programming language. 



HTML or XML document 
(marked-up text) 



Document Object Model (DOM) 

(nodes, properties, methods, & 
event handlers) 



JavaScript 

(expressions, statements, 
functions, & objects) 



On one level, this separation is a good thing. It means that one specification exists for basic 
programming concepts and syntax that could become the programming language in any number of 
other environments. You can think of the core language as basic wiring. When you know how electric 



17 



Part I: Getting Started with JavaScript 



wires work, you can connect them to all kinds of electrical devices. Similarly, JavaScript today is used 
to wire together elements in an HTML document. Tomorrow, operating systems could use the core 
language to enable users to wire together desktop applications that need to exchange information 
automatically. 

At the ends of today's JavaScript wires inside browsers are the elements on the page such as para- 
graphs (p), images (img), and input fields (i nput). In programming jargon, these items are known 
as document objects. By keeping the specifications for document objects separate from the wires that 
connect them, you can use other kinds of wires (other languages) to connect them. It's like designing 
telephones that can work with any kind of wire, including a type of wire that hasn't been invented 
yet. Today, the devices can work with copper wire or fiber-optic cable. You get a good picture of this 
separation in Internet Explorer, whose set of document objects can be scripted with either JavaScript 
or VBScript. The same objects can be connected with either of those two different sets of wiring. 

The separation of core language from document objects enables each concept to have its own 
standards effort and development pace. But even with recommended standards for each factor, each 
browser maker is free to extend the standards. Furthermore, authors may have to expend more effort 
to devise one version of a page or script that plays on multiple browsers, unless the script adheres to a 
common denominator (or uses some other branching techniques to let each browser run its own way). 

Core language standard 

Keeping track of JavaScript language versions requires a brief history lesson. The first version of 
JavaScript (in Netscape Navigator 2) was version 1, although that numbering was not part of the 
language usage. JavaScript was JavaScript. Version numbering became an issue when Navigator 3 was 
released. The version of JavaScript associated with that Navigator version was JavaScript 1.1. The 
first appearance of the Navigator 4 generation increased the language version one more notch with 
JavaScript 1.2. 

Microsoft's scripting effort contributes confusion for scripting newcomers. The first version of Internet 
Explorer to include scripting was Internet Explorer 3. The timing of Internet Explorer 3 was roughly 
coincidental to Navigator 3. But as scripters soon discovered, Microsoft's scripting effort was one gen- 
eration behind. Microsoft did not license the JavaScript name. As a result, the company called its 
language JScript. Even so, the HTML tag attribute that lets you name the language of the script inside 
the tags could be either JScript or JavaScript for Internet Explorer. Internet Explorer 3 could under- 
stand a JavaScript script written for Navigator 2. 

During this period of dominance by Navigator 3 and Internet Explorer 3, scripting newcomers were 
often confused because they expected the scripting languages to be the same. Unfortunately for the 
scripters, there were language features in JavaScript 1.1 that were not available in the older JavaScript 
version in Internet Explorer 3. Microsoft improved JavaScript in IE3 with an upgrade to the .dll file 
that gives IE its JavaScript syntax. However, it was hard to know which .dll is installed in any given 
visitor's IE3. The situation smoothed out for Internet Explorer 4. Its core language was essentially up 
to the level of JavaScript 1.2, as in early releases of Navigator 4. Almost all language features that were 
new in Navigator 4 were understood when you loaded the scripts into Internet Explorer 4. Microsoft 
still officially called the language JScript. 

While all of this jockeying for JavaScript versions was happening, Netscape, Microsoft, and other con- 
cerned parties met to establish a core language standard. The standards body is a Switzerland-based 
organization originally called the European Computer Manufacturer's Association and now known 
simply as ECMA (commonly pronounced "ECK-ma"). In mid-1997, the first formal language speci- 
fication was agreed on and published (ECMA-262). Due to licensing issues with the JavaScript name, 
the body created a new name for the language: ECMAScript. 



18 



Chapter 2: Developing a Scripting Strategy 



With only minor and esoteric differences, this first version of ECMAScript was essentially the same 
as JavaScript 1.1, used in Navigator 3. Both Navigator 4 and Internet Explorer 4 officially supported 
the ECMAScript standard. Moreover, as happens so often when commerce meets standards bodies, 
both browsers went beyond the ECMAScript standard. Fortunately, the common denominator of this 
extended core language is broad, lessening authoring headaches on this front. 

JavaScript version 1.3 was implemented in Netscape Navigator 4.06 through 4.7x. This language ver- 
sion is also the one supported in IE5, 5.5, and 6. A few new language features are incorporated in 
JavaScript 1.5, as implemented in Mozilla-based browsers (including Navigator 6 and later). A few 
more core language features were added to JavaScript 1.6, first implemented in Mozilla 1.8 (Firefox 
1.5, and yet more to JavaScript 1.8 in Firefox 3). 

In practice, so many browsers in use today support all but a few leading-edge features of 
the Mozilla browsers, that JavaScript version numbers are mostly irrelevant. Other compat- 
ibility issues with older browsers will likely get in your way before core language problems 
do. The time has come to forget about elaborate workarounds for the inadequacies of the 
oldest browsers. 

Document object model 

If prevalent browsers have been close to one another in core JavaScript language compatibility, nothing 
could be further from the truth when it comes to the document objects. Internet Explorer 3 based its 
document object model (DOM) on that of Netscape Navigator 2, the same browser level it used as a 
model for the core language. When Netscape added a couple of new objects to the model in Navigator 
3, the addition caused further headaches for neophyte scnpters who expected those objects to appear 
in Internet Explorer 3. Probably the most commonly missed object in Internet Explorer 3 was the 
image object, which lets scripts swap the image when a user rolls the cursor atop a graphic — mouse 
rollovers, they're commonly called. 

In the level 4 browsers, however, Internet Explorer's DOM jumped way ahead of the object 
model that Netscape implemented in Navigator 4. The two most revolutionary aspects of IE4 
were the ability to script virtually every element in an HTML document and the instant reflow 
of a page when the content changed. This opened the way for HTML content to be genuinely 
dynamic without requiring the browser to fetch a rearranged page from the server. NN4 imple- 
mented only a small portion of this dynamism, without exposing all elements to scripts or 
reflowing the page. It introduced a proprietary layering concept that was abandoned at the end of the 
Navigator 4.x lifetime. Inline content could not change in NN4 as it could in IE4. Suffice it to say 
that IE4 was an enviable implementation. 

At the same time, a DOM standard was being negotiated under the auspices of the World Wide 
Web Consortium (W3C). The hope among scripters was that after a standard was in place, it would 
be easier to develop dynamic content for all browsers that supported the standard. The resulting 
standard — the W3C DOM — formalized the notion of being able to script every element on the 
page, as in IE4. But it also invented an entirely new object syntax that no browser had used. The race 
was on for browsers to support the W3C DOM standards. 

An arm of the Netscape company called Mozilla.org was formed to create an all-new browser 
dedicated to supporting industry standards. The engine for the Mozilla browser became the basis 
for the all-new Navigator 6. It incorporated all of the W3C DOM Level 1 and a good chunk of 
Level 2. Mozilla 1.01 became the basis for the Netscape 7 browser, whereas Netscape 7.1 was built on 
the Mozilla 1.4 generation. In the summer of 2003, Netscape's parent company, AOL Time Warner, 
decided to end further Netscape-branded browser development. The work on the underlying Mozilla 
browser, however, continues under an independent organization called The Mozilla Foundation. 



19 



Part I: Getting Started with JavaScript 



Mozilla-based browsers, and others using the same engine (such as Firefox and Camino), continue to 
be upgraded and released to the public. The Mozilla engine arguably offers the most in-depth support 
for the W3C DOM standards. 

Even though Microsoft participated in W3C DOM standards development, IE5 and 5.5 imple- 
mented only some of the W3C DOM standard — in some cases, just enough to allow simple 
cross-browser scripting that adheres to the standard. Microsoft further filled out W3C DOM 
support in IE6, but chose to omit several important parts. Despite the long time gap between 
releases of IE6 and IE7, the latter included no additional W3C DOM support — much to 
the chagrin of web developers. IE8 finally did some significant catching up with the W3C 
DOM specification, with a switch to put IE8 back into IE7-compatibility mode for support of 
legacy scripts. 

The Apple Safari browser has raced forward in its comparatively short life to offer substantial W3C 
DOM support. This is especially true of version 2, which was first released as part of Mac OS X ver- 
sion 10.4. 

With this seemingly tortuous history of DOM development and browser support leading to the present 
day, you may wonder how anyone can approach DOM scripting with hope of success. Yet you'd be 
amazed by how much you can accomplish with today's browsers. You'll certainly encounter compat- 
ibility issues along the way, but this book will guide you through the most common problems and 
equip you to tackle others. 

Laying a good foundation with markup 

When the HTML markup on a page conforms to uniform public standards, browsers from different 
manufacturers tend to treat it similarly. However, in order to support the millions of web pages from 
past years, browsers also take a stab at guessing the author's intent when the markup differs from the 
specs. Because this sort of "guessing," for the most part, isn't prescribed in the HTML standards, the 
various browser manufacturers have come up with their own very different solutions. Therefore, you 
will get more consistent results and build more bullet-proof sites if your markup is easily parsable and 
error-free. 

We encourage you produce markup that conforms to the W3C specification — for example, the 
HTML 4.01 spec at http : / /www.w3 . org/TR/html 4/. It's a good idea to rely on tools such as the 
W3C HTML Validator (http://validator.w3.org/) to check your markup against the standard. 
Beyond that, be consistent in your own work even when the spec is loose — for example, we suggest 
that you close all tags such as td and 1 i even if the spec and the Validator don't require it. Examine 
and mimic the kind of markup produced by JavaScript using DOM methods, and you'll be doing fine. 

Cascading Style Sheets 

Navigator 4 and Internet Explorer 4 were the first browsers to claim compatibility with a W3C rec- 
ommendation called Cascading Style Sheets Level 1 (CSS1). This specification provided designers an 
organized way to customize the look and feel of a document (and thus minimized the HTML in each 
tag). As implementations go, NN4's had a lot of rough edges, especially when trying to mix style 
sheets and tables. But IE4 was no angel, either, especially when one compared the results of style 
sheet assignments as rendered in the Windows and Macintosh versions of the browser (developed by 
two separate teams). 

CSS Level 2 adds more style functionality to the standard; IE6, Mozilla-based browsers, and Safari 
support a good deal of Level 2 (albeit unevenly) with the latest versions, such as Mozilla 1.84- and 



20 



Chapter 2: Developing a Scripting Strategy 



Safari 2+, and they are beginning to support CSS Level 3 features. Rendering of styled content is more 
harmonious among browsers, largely thanks to guidelines about how styles should render. Complex 
layouts, however, still need careful tweaking from time to time because of different interpretations of 
the standard. 

JavaScript plays a role in style sheets in IE4+, Mozilla, and Safari because those browsers' object 
models permit dynamic modification to styles associated with any content on the page. Style sheet 
information is part of the object model and therefore is accessible and modifiable from JavaScript. 

Standards compatibility modes 
(DOCTYPE switching) 

Both Microsoft and Netscape/Mozilla discovered that they had, over time, implemented CSS features in 
ways that ultimately differed from the published standards that came later (usually after much wran- 
gling among working-group members). To compensate for these differences and make a clean break to 
be compatible with the standards, the major browser makers decided to let the page author's choice of 
< ! DOCTYPE) header element details determine whether the document was designed to follow the old 
way (sometimes called quirks mode) or the standards-compatible way. The tactic, known informally as 
DOCTYPE switching, is implemented in Internet Explorer 6 and later, Internet Explorer 5 for the Mac, 
and all Mozilla-based browsers. 

Although most of the differences between the two modes are small, there are some significant 
differences between them in Internet Explorer 6 and later, particularly when styles or DHTML 
scripts rely on elements designed with borders, margins, and padding. Microsoft's original 
box model measured the dimensions of elements in a way that differed from the eventual 
CSS standard. 

To place the affected browsers in CSS standards-compatible mode, you should include a <!D0CTYPE> 
element at the top of every document that specifies one of the following statements: 

< ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional //EN" 
"http://www.w3.org/TR/REC-html40/loose.dtd"> 

< ! DOCTYPE HTML PUBLIC " -//W3C//DTD HTML 4.0 Frameset/ / EN " 
"http://www.w3.org/TR/REC-html40/frameset.dtd"> 

< ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" 

"http://www.w3.org/TR/REC-html40/strict.dtd"> 

< ! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transi ti onal // EN " 

"http : //www. w3 . org/TR/xhtml 1/DTD/xhtml 1 -transi ti onal. dtd"> 

< ! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 

"http : / /www. w3 . org/TR/xhtmll/DTD/xhtmll -frame set. dtd"> 

< ! DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Strict//EN" 

"http://www.w3.org/TR/xhtml 1/DTD/xhtml 1 -strict. dtd"> 

< ! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 

"http://www.w3.org/TR/xhtml 11 /DTD/xhtml 1 1 . d t d " > 

Be aware, however, that older versions of Internet Explorer for Windows, such as Internet 
Explorer 5 or Internet Explorer 5.5, are ignorant of the standards-compatible mode and 



21 



Part I: Getting Started with JavaScript 



will use the old Microsoft quirks mode regardless of your < ! DOCTYPE) setting. Still, using 

the standards-compatible mode DOCTYPE is more likely to force your content and style sheets to 

render similarly across the latest browsers. 

Dynamic HTML and positioning 

Perhaps the biggest improvements to the inner workings of the Level 4 browsers from both Netscape 
and Microsoft revolved around a concept called Dynamic HTML (DHTML). The ultimate goal of 
DHTML was to enable scripts in documents to control content, content position, and content appear- 
ance in response to user actions. To that end, the W3C organization developed another standard for 
the precise positioning of HTML elements on a page, as an extension of the CSS standards effort. The 
CSS-Positioning recommendation was later incorporated into the CSS standard, and both are now 
part of CSS Level 2. With positioning, you can define an exact location on the page where an element 
should appear, whether the item should be visible, and what stacking order it should take among all 
the items that might overlap it. 

IE4+ adheres to the positioning-standard syntax and makes positionable items subject to script con- 
trol. Navigator 4 followed the standard from a conceptual point of view, but it implemented an alter- 
native methodology involving an entirely new, and eventually unsanctioned, tag for layers. Such posi- 
tionable items were scriptable in Navigator 4 as well, although a lot of the script syntax differed from 
that used in Internet Explorer 4. Fortunately for DHTML authors, Mozilla, through its adherence to 
the CSS standard, is more syntactically in line with the DHTML style properties employed in IE44-. 

Of more interest these days is the ability to modify the inline content of a web page without reloading 
the entire page. Fundamental standards from the W3C DOM Level 1 are supported by a wide range of 
browsers, including IE54-, Mozilla, Safari, and Opera. You can accomplish quite a lot using the same 
basic syntax across all of these browsers. Some challenges remain, however, as you'll see throughout 
this book. 



Developing a Scripting Strategy 

How do you create web pages that work well across the board? Browsers representing the latest gen- 
eration contain a hodgepodge of standards and proprietary extensions. Even if you try to script to a 
common denominator among today's browsers, your code probably won't take into account the earlier 
versions of both the JavaScript core language and the browser DOMs. 

The true challenge for authors is determining the audience for which scripted pages are intended. 
Each new browser generation not only brings with it new and exciting features you are probably eager 
to employ in your pages, but also adds to the fragmentation of the audience visiting a publicly acces- 
sible page. It can take months for the latest upgrade of a browser to supplant the previous version 
among its users, and some people seldom or never upgrade unless the new browser comes via a new 
computer or operating system upgrade. As a result, web developers are writing for an incredibly mixed 
audience of browser makes and models, including some of the latest mobile devices that don't support 
JavaScript. Add to that all the user agents that aren't visual browsers, such as screen readers and search 
engines. How to cope? 

Graceful degradation and progressive enhancement 

At this stage in the history of scriptable browsers, most web surfers arrive at our sites with browsers 
equipped with support for at least simple W3C DOM and DHTML capabilities. But "most" isn't every- 
one by a long shot, so it is our obligation to apply scripting in the additive, or value-added, manner 



22 



Chapter 2: Developing a Scripting Strategy 



known as progressive enhancement. By this we mean that your pages should convey their primary infor- 
mation to nonscriptable browsers designed for users with vision or motor-skill impairments, as well 
as less-feature-rich browsers built into the latest cellular phones. On top of that, your scripting efforts 
can give visitors with recent scriptable browsers a more enjoyable experience — better interactivity, 
faster performance, and a more engaging presentation. You will not only be contributing to the state 
of the art, but also carrying on the original vision of scripting in the browser. 

In an early stage of the Web's evolution, many web site developers included the fancy features of 
the latest browser releases without much concern for folks who hadn't upgraded their browsers or 
switched from brand X to brand Y. This meant that a lot of new web sites were cosmetically — or, 
worse, functionally — broken for a lot of visitors. It was common to see banners explaining that "this 
website is viewed best in" such-and-such a browser, and it was left to the visitor to put up with the 
mess, or to install a new browser. 

Over the years, web site producers have acquired two exciting new features that have changed 
our approach to browser support: the online business model and the social conscience. Excluding 
potential web site visitors from both commercial and non-profit sites is recognized as fiscally unwise. 
Excluding users of assistive technology is regarded as unjust — not to mention actionable in an 
increasing number of jurisdictions. As web developers, our concern isn't just a few obsolete browsers 
that can't run JavaScript. There are many other user agents that don't or can't support scripting, 
including search engines, some mobile devices, and some screen-readers and other assistive UAs. 
A lot of people simply turn off JavaScript support in their browsers. Some corporate firewalls strip 
JavaScript out of incoming web pages so that even entirely JavaScript-capable browsers within the 
organization do not see it or run it. Web stats are all over the map, but some estimates of the 
percentage of web site visitors who run without JavaScript for all of these reasons are 10% or higher. 
Even if it were only 1%, it would be significant. Imagine that you're holding the front door for 
customers at a physical storefront, and you choose to slam the door in the face of one out of every 
hundred people who approach. How long would you keep your job? 

Graceful degradation is an approach to system design that provides fall-backs in case of failure. 
In web design, this means providing a lower level of appearance or functionality if the user 
agent can't handle any of the advanced technology that makes up the page. The problem with 
graceful degradation is the way it's been incorporated into site production. Developers who cut 
their teeth in the bad old days, and those who were trained by them, continued to build sites 
primarily for the most advanced and well-equipped browsers and then, as a final step or retrofit, 
tried to accommodate the rest. This approach adds a lot of work to the final stages of a project 
for the sake of a minority of users, so in the real world of web design, graceful degradation is 
often sacrificed due to all-too-common limits on time, money, and altruism. The result is an 
Internet full of web sites that still fail very ungracefully for a significant number of potential 
visitors. 

Progressive enhancement is a newer approach that does justice to graceful degradation. A web site is 
first designed to run in all user agents, and then enhancements are added to make the user's experi- 
ence faster or richer if they're using a more sophisticated browser. This ensures essential functionality 
for every reader (human or machine) and supports the fancy browsers without sacrificing the simpler 
ones. It puts the vegetable course before the dessert and the horse before the cart. It makes sure the 
car has a working engine before adding the chrome and the sound system. 

One way we manifest the principle of progressive enhancement in our work is by building pages that 
work in the absence of JavaScript. This might seem like heresy in a JavaScript "Bible," but the bottom 
line is that JavaScript is one of many tools we use to accomplish our work. No single tool is so shiny 
and clever that it should upstage the real star of the show — the web site visitor. 



23 



Part I: Getting Started with JavaScript 



Separation of development layers 

Another important principle in modem web design is the separation of layers of development. 
The main layers we work with are the content of a page (such as text and image names), 
its structure in HTML markup, its behavior in JavaScript, and its presentation in CSS (see 
Figure 2-2). The more you can keep these layers separate, the easier it will be to build, modify, and 
re-use your work. 



FIGURE 2-2 



Four layers of client-side web development. 



behavior 
(JavaScript) 



presentation 
(CSS) 



structure 
(DOM /HTML markup) 



content 
(text & URIs of images etc.) 



marked-up content 
(HTML document) 



Old-school web pages are easy to spot: just look at the HTML source, and you'll see JavaScript and 
styling attributes embedded in the markup. This is like a house built with the wiring and pipes 
embedded in cement walls. If you want to change or replace the wiring, you've got a real mess 
on your hands. These cemented pages are redundant, since identical features on different pages 
require the same bloated markup to be downloaded each time. For that reason, they're also slower to 
download. 

With separated layers, each component file is fairly trim and fast to download, and if the same style 
sheet or JavaScript script applies to more than one page, as is often the case, the response time is even 
faster since the browser caches (stores) files it has already fetched from the server. Web site develop- 
ment and redesign are also made more efficient because several people can work on different layers 
without stepping on one another's toes. It becomes possible to develop modules of markup, script, and 
style that can more easily be tweaked and re-used for future projects. 

Separate development layers aren't unrelated. Just the opposite, in fact: the style sheet and JavaScript 
code refer to and depend on the HTML markup structure, tags, and attributes. They are hands whose 
fingers are designed to mesh perfectly, but they are still separate hands. 

The first step in separating layers is literally to create separate files for your HTML, JavaScript, and 
CSS. (The HTML files you'll see in this book are already combinations of markup and content, which, 
in the everyday world of web production, are often a merger of HTML templates and database fields 
performed by a server-side script.) 

Separation of layers is also an approach we can take to our scripting logic. JavaScript has the ability 
to write a chunk of cemented markup and text to a document in one operation, but if we separate 
the new structural elements from their content in our script, we end up with code that is easier to 



24 



Chapter 2: Developing a Scripting Strategy 



debug and re-use, and that contains fewer errors. Similarly, JavaScript can directly tweak the styling of 
an element on a page, changing its color or size or position, but instead, if we simply assign an id or 
class that is separately defined in the style sheet, then a graphic designer can change that presentation 
without anyone having to modify the JavaScript. 

Further reading 

Progressive Enhancement: Paving the Way for Future Web Design, by Debra Chamra 

http://hesketh.com/publications/articles/progressive-enhancement- 
paving-the-way-for/ 

Graceful Degradation & Progressive Enhancement, by Tommy Olsson 

http://accessites.org/site/2007/02/graceful-degradation-progressive- 
enhancement/ 

Progressive enhancement, in Wikipedia 

http://en. wikiped ia.org/wiki /Progress i ve_enhancement 



25 



Selecting and Using 
Your Tools 



CHAPTER 



J 




In this chapter, you set up a productive script writing and previewing 
environment on your computer and learn where to find valuable resources 
on the Web. We also produce sample HTML, JavaScript, and CSS files to 
demonstrate how to use these tools to create real web pages. 

Because of differences in the way various personal computing operating systems 
behave, we present details of environments for two popular variants: Windows 
(95 through XP) and Mac OS X. For the most part, your JavaScript authoring 
experience will be the same regardless of the operating system platform you 
use — including Linux or Unix. Although there may be slight differences in 
font designs, depending on your browser and operating system, the informa- 
tion remains the same. Most illustrations of browser output in this book are 
made from the Windows XP versions of Internet Explorer and Firefox. If you 
run another browser or version, don't fret if every pixel doesn't match the illus- 
trations in this book. 



IN THIS CHAPTER 



How to choose basic 
JavaScript authoring tools 

How to set up your authoring 
environment 

How to enter a simple script 
to create a web page 



The Software Tools 



The best way to learn JavaScript is to type the HTML and scripting code into 
documents in a text editor. Your choice of editor is up to you, although we pro- 
vide some guidelines for choosing. 



Choosing a text editor 



For the purposes of learning JavaScript in this book, avoid WYSIWYG (What 
You See Is What You Get) web page authoring tools such as FrontPage 
and Dreamweaver. These tools may come in handy later for molding your 
content and layout. But the examples in this book focus more on script content 
(which you must type anyway), so there isn't much HTML that you have to 
type. Files for all complete web page listings in this book (except for the tutorial 
chapters) also appear on the companion CD-ROM. 



27 



Part I: Getting Started with JavaScript 



An important factor to consider in your choice of editor is how easy it is to save standard text files 
with an . html filename extension. In the case of Windows, any program that not only saves the file 
as text by default, but also enables you to set the extension to . htm or . html , prevents a great deal 
of problems. If you use Microsoft Word, for example, the program tries to save files as binary Word 
files — something that no web browser can load. To save the file initially as a . txt or .html exten- 
sion file requires mucking around in the Save As dialog box. This is truly a nuisance. 

Perhaps more importantly, a word processor such as Microsoft Word opens with a lot of 
default settings that may make desktop publishing easier but can frustrate a programmer, 
such as inserting spaces around words and automatically replacing straight quotes with curly quotes. 
Setting its defaults to make it programmer-friendly will make it less useful as a word processor. 

Finally, we urge you not to create documents in Word and "save them as a web page." This will gen- 
erate an HTML document that will look much like the word processing document on which it's based, 
but the actual HTML coding it produces will be bloated and redundant — a far cry from the sleek 
and elegant code that we hope you will be producing after you read this book. Word just isn't the 
right tool for this job. 

Nothing's wrong with using bare-essentials text editors. In Windows, that includes the Word- 
Pad program or a more fully featured product such as Visual Studio or the shareware editor 
called TextPad. For Mac OS X, the bundled TextEdit application is also fine. Favorites among 
Mac HTML authors and scripters include BBEdit (Bare Bones Software) and SubEthaEdit 
(www. codingmonkeys.de/subethaedit). 

Choosing a browser 

The other component that is required for learning JavaScript is the browser. You don't have to be 
connected to the Internet to test your scripts in the browser. You can perform all testing offline. This 
means you can learn JavaScript and create cool, scripted web pages with a laptop computer — even 
on a boat in the middle of an ocean. 

The browser brand and version you use are up to you. Because the tutorial chapters in this book 
teach the W3C DOM syntax, you should be using a recent browser. Any of the following will get you 
through the tutorial: Internet Explorer 5 or later (Windows or Macintosh); any Mozilla-based browser 
(including Firefox, Netscape 7 or later, and Camino); Apple Safari; and Opera 7 or later. 

Note 

Many example listings in Parts III and IV of this book demonstrate language or document object model (DOM) 
features that work on only specific browsers and versions. Check the compatibility listing for that language or 
DOM feature to make sure you use the right browser to load the page. ■ 



Setting Up Your Authoring Environment 

To make the job of testing your scripts easier, you want to have your text editor and browser running 
simultaneously. You need to be able to switch quickly between editor and browser as you experiment 
and repair any errors that may creep into your code. The typical workflow entails the following steps: 

1 . Enter HTML, JavaScript, and CSS into the source documents in the text editor. 

2. Save them to disk. 

3. Switch to the browser. 

28 



Chapter 3: Selecting and Using Your Tools 



4. Do one of the following: 

• If this is a new document, open the file through the browser's Open menu. 

• If the document is already loaded, reload the file into the browser. 

Steps 2 through 4 are actions you will take frequently. We call this three-step sequence the 
save-switch-reload sequence. You will perform this sequence so often as you script that the physical act 
will quickly become second nature to you. How you arrange your application windows and effect the 
save-switch-reload sequence varies according to your operating system. 

In web site production, after you tweak your markup, style sheet, and scripts to your liking on your 
own computer, you'll upload them to your server using an FTP (File Transfer Protocol) program. 

There are also online editors, but for now let's keep it simple. One of the advantages of doing your 
work off-line on your own computer is that you don't even have to have an active Internet connection 
during this stage of web site development. 



Windows 

You don't have to have either the editor or browser window maximized (at full screen) to take advan- 
tage of them. In fact, you may find them easier to work with if you adjust the size and location of 
each window so that both windows are as large as possible, while still enabling you to click a sliver 
of the other's window. Or, you can leave the taskbar visible so you can click the desired program's 
button to switch to its window (see Figure 3-1). A monitor that displays more than 800x600 pixels 
certainly helps in offering more screen real estate for the windows and the taskbar. 



FIGURE 3-1 



Editor and browser window arrangement in Windows XP. 



S3 





ran 


.1 - w ■* ::. H 4 'A 





^tUlE Ub IALECk3 ldW>3M |C£i]F:-fcC.. I» I. 
TBT >±1] 
if |E*jPcll I 

Li r.ECT*a* cMiftit ■- »wie±i^| -| 

Eitf - e&c jh br. . cm e E. L em daJ y Ed i oh-j m \ 

■ KlZK > 

»1 ■ K]K[ 

'I 

:■ iIh ! 

ou&drc . Eua?. 0*r*r,LE Uw-ie k donm .hodf .pirinHuii 

> 

!.'*■' LadferC ■ - - 
h'tkt L, iJEE-JE-.. EXL 

i± |n| I 



■ 



□ uptc +■ "0±LL Uadu at < r ■+ ctij.Eb^ 



- 



29 



Part I: Getting Started with JavaScript 



In practice, however, the Windows Alt+Tab task-switching keyboard shortcut makes the job 
of the save-switch-reload steps outlined earlier a snap. If you run Windows and also use a 
Windows-compatible text editor (which more than likely has a Ctrl+S file-saving keyboard shortcut), 
you can effect the save-switch-reload sequence from the keyboard with your the left hand: Ctrl+S 
(save the source file), Alt+Tab (switch to the browser), and Ctrl+R (reload the saved source file). 

As long as you keep switching between the browser and the text editor via Alt+Tab task-switching, 
either program is always just an Alt+Tab away. 

Mac OS X 

In Mac OS X, you can change between your text editor and browser applications via the Dock, or, 
more conveniently, by pressing 3€+Tab. As long as you stay in those two applications, the other pro- 
gram is only one 3€+Tab away (see Figure 3-2). 

With this setup, the save-switch-reload sequence is a simple affair: 

1 . Press S€+S (save the source file). 

2. Press S€+Tab (switch to the browser). 

3. Press 3€+R (reload the saved source file). 

To return to editing the source file, press 3€+Tab again. 



FIGURE 3-2 



Editor and browser window arrangement on the Macintosh screen. 



* ilFd-i - - rai T+ j FrfF lurti Hull Hirti^i W.vtw, t> j, -Hri;- \f iU -C ps5N- Uaa 4 II Imi 




30 



Chapter 3: Selecting and Using Your Tools 



Reloading issues 

For the most part, a simple page reload is enough to let you test a revised version of a script right 
away. But sometimes the browser's cache (with its default settings) can preserve parts of the previous 
page's attributes when you reload, even though you have changed the source code. To perform a more 
thorough reload, hold down the Shift key while clicking the browser's Reload/Refresh button. Alterna- 
tively, you can turn off the browser's cache in the preferences area, but that setting may negatively 
affect the overall performance of the browser during your regular web surfing. 

Validate, Validate, Validate 

You can save yourself hours of debugging by checking to make sure your HTML is valid. If your 
markup is flawed, chances are your JavaScript and CSS will not work as expected, because they both 
depend on HTML elements (tags) and their attributes. The more closely your markup matches the 
industry-standard specs, the more likely it is that you'll get consistent results across browsers that are 
all approaching the holy grail of web standards conformance. You should always proofread your own 
code, of course, but an automated validation tool helps for large, complicated pages, and for program- 
mers who are still learning all the rules for correct markup. 

The World Wide Web Consortium (W3C), which wrote the HTML specification, has 
developed just such a validator. It checks a page with the rules specific to the DOCTYPE 
that begins the page. Besides catching our typos, an added advantage of running the Validator is that 
it helps us leam the fine points of HTML markup. Now repeat after me: The Validator Is My Friend. 

The W3C Validator is at http://validator.w3.org/. It offers three ways to input your 
markup — by entering its online URL, by uploading the .html file from your computer, and by 
copying and pasting the markup into the Validator directly. Then, click the Check button and read 
the results. Often, a single error of markup will result in several items in the Validator error report. If 
it found any errors in your markup, make the necessary corrections and run your code through the 
Validator again until you get the green success banner. 

Using the Validator will probably make you curious about the HTML specifications. You can read 
them on the W3C web site: 

• HTML 4.01: http://www.w3.org/TR/html4/ 

• HTML5: http://www.w3.org/TR/html5/ 

• XHTML 1.0: http://www.w3.org/TR/xhtmll/ 

As time goes on, you'll discover other useful specs and validators out there, such as those for CSS 
(Cascading Style Sheets) and web accessibility guidelines: 

• CSS 2.1 Specification: http://www.w3.org/TR/CSS21/ 

• CSS Validation Service: http://jigsaw.w3.org/css-validator/ 

• Web Content Accessibility Guidelines: 

http://www.w3.org/TR/1999/WAI-WEBC0NTENT-19990505/ 

• Web Accessibility Evaluation Tools: http : / /www.w3 . o rg/ WA I / ER/ 1 ool s/ 

Creating Your First Script 

To demonstrate how we'll use these tools, let's create a classic "Hello, World" page in three stages: first 
as plain HTML, then augmented with JavaScript, and finally styled with CSS. 



31 



Part I: Getting Started with JavaScript 



For the sake of simplicity, the kind of scripts we're building now are the kind that run automatically, 
immediately after the browser loads the HTML page. Although all scripting and browsing work here is 
done offline, the behavior of the page is identical if you place the source file on a server and someone 
accesses it through the web. 

To begin, open your text editor and your browser. Also run Windows File Manager/Macintosh Finder 
to create a folder in which to save your scripts. 

Stage 1 : static HTML 

Create a new text file and enter the markup in Listing 3-1. 



LISTING 3-1 



Source Code for hello-world. hlml 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v = "content-type" content="text/html ;charset=utf -8"> 

<title>Hello, Worl d</ti tl e> 
</head> 
<body> 

<hl>Hello, World</hl> 

<p>This is HTML.</p> 
</body> 
</html > 



Save this file to your hard drive as hel 1 o-worl d . html , and open it in your browser. Figure 3-3 
shows the page as it appears in the browser after you're finished. The precise appearance (or voice, if 
you're using a screen-reader) may vary slightly from one browser to the next, since at this point we're 
relying on the default style sheet in the browser to render the page. 

The head of this page contains two required elements: a met a tag that declares the MIME type and 
character set, and a title. The body consists of a headline and a paragraph of text, pure and simple. 



Stage 2: connecting with JavaScript 

Now let's add JavaScript to the page. Create a new text file on your computer and enter Listing 3-2. 
Be sure and spell everything exactly, including upper- and lowercase: 



LISTING 3-2 



Source Code for hello-world.js 

var today = new Date(); 

var msg = "This is JavaScript saying it's now " + today . toLocal eStri ng () ; 
al ert(msg) ; 



32 



Chapter 3: Selecting and Using Your Tools 



FIGURE 3-3 



The static HTML file displayed in a browser. 



" Hi- fa. Wm I J Wiidawi fatiTiH-t I jc|iki rr 



- |> Clh-l5g*p»l ' .'l»l- >|l>' 
, 1MB ^hHk.ffMI 



JLcllos Work! 

TfcinhTVC 



J • • -'1 f 



Save this file as hel 1 o-worl d . j s. It consists of just three JavaScript statements: the first gets the 
current date, the second composes a brief message, and the third displays the message. 

To enable this JavaScript program to act on your HTML document, add a new scri pt tag to the 
head section of the HTML (shown highlighted in Listing 3-3): 



LISTING 3-3 



Revised Source Code for hello-world.html 



<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Hello, Worl d</titl e> 

<scri pt type="text/ javascri pt" src=" hell o-worl d.js"X/script> 

</head> 



33 



Part I: Getting Started with JavaScript 



The HTML scri pt element tells the browser the type and name of the script file to combine with 
the document. Because the src (source) attribute doesn't include a path, the system assumes it's in 
the same folder as the HTML file. Unlike the met a tag, every <scri pt> tag must be closed with 
</script>. 

When you save the new JavaScript file and the modified HTML file, reload the HTML file in your 
browser. It should look something like Figure 3-4. 



FIGURE 3-4 



A JavaScript alertQ. 



- Hollo, Wiitltl - Windows Internet Explorer 




-Inlxi 


Q » |a_ CiysmStnpt BMeViello-wirtl.litml 






| Pie Edi '.v.v Favorite* rooh Help 


FMatet , Lonncrtng. . 




: in • Ptge' Saf=rr- T«u- ii 





This is JnvnSmpl saying n's now fiiMSm/, June iti, 2009 3:12:54 AM 



Waling lor IHe:OTCtfJswStrlpt%M!lblefhelb world. tiM. ■ ^ My Computer , - *, lOMi ' ; ; 



The text we passed to alert( ) appears in what's called a modal dialog. "Modal" means that you 
can't do anything more with the application (your browser) until you close the dialog. Notice that 
the HTML headline and paragraph seem to have disappeared! No worries; they will appear as soon as 
you click OK on the modal dialog. Why? The browser renders the HTML file from top to bottom. It 
encounters the script tag in the head and runs the named JavaScript program before it renders the 
HTML body. In this case, the modal dialog produced by the al ert ( ) method halts the rendering of 
the rest of the page until we respond. 



34 



Chapter 3: Selecting and Using Your Tools 



Stage 3: styling with CSS 

Let's add some styling to the page so that you can see how HTML and CSS interact. Create a new text 
file on your computer and enter Listing 3-4: 



LISTING 3-4 



Source Code for hello-world. ess 

hi 

{ 

font : italic 3em Ari al ; 

} 
P 

{ 

margin-left: 2em; 
font-size: 1.5em; 

1 



Save this file to your hard drive as hel 1 o-worl d . ess. 

This style sheet applies a particular font and color to all the hi elements on the page, and a left mar- 
gin and font-size to all the p elements. Of course, in our document, there is only one of each. 

To enable this style sheet to affect your HTML document, add a 1 i n k tag to the h e a d section of the 
HTML (shown highlighted in Listing 3-5): 



LISTING 3-5 



Revised Source Code for hello-world.html 



<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Hello, Worl d</titl e> 

<script type=" text/javascript" src= "hello-world. js"X/script> 
< 1 ink type="text/css" rel ="styl esheet" href =" hell o-worl d . ess "> 

</head> 



The link element tells the browser the type, relationship, and name of the style sheet to combine 
with the document. Note that, like the meta tag and unlike the scri pt tag, 1 i nk is an "empty" tag 
and does not take a separate closing tag. Because the s r c (source) attribute doesn't include a path, 
the system assumes it's in the same folder as the HTML file. Every <scri pt> tag must be closed with 
</script>. 

When you save these files and reload the HTML document in your browser (and click OK on that 
modal dialog), it will look something like Figure 3-5. 



35 



Part I: Getting Started with JavaScript 



FIGURE 3-5 



A styled page. 



C Hi* Ho, Wnrlri Windows [ni^rnct f xplnr^r 




=MiSJ 


• ■ |*? Cd+^n^cfifii B^v>e'i.ris**-*«ortfl,hciiii 


-|K » HI ., 


>j ■ 


Flift ErCfTt VI WW FMSntM FDOlB H*p 




| ft * a • w-" 


W wtav- t*»- «- c 


He//o, Wor/tf 






This is HTML. 

Done 


rrrrrr^^ 





36 



CHAPTER 



JavaScript Essentials 



When first learning to use JavaScript in the context of the web browser 
environment, it can be easy to confuse the objects of the JavaScript 
language with the document objects that we control with JavaScript. 
It's important to separate the language from the Document Object Model (DOM) 
to help you make important decisions when designing JavaScript-enhanced 
pages. You may come to appreciate the separation in the future if you use 
JavaScript for other object models, such as in server-side programming or 
scripting Flash animations. All the basics of the language are identical from one 
context to another; only the objects differ. 

This chapter introduces many aspects of the core JavaScript language, par- 
ticularly as they relate to deploying scripts in a world in which visitors to 
your pages may use a wide variety of browsers. Along the way, youll receive 
additional insights into the language itself. Fortunately, browser differences, 
as they apply to JavaScript, have lessened considerably as modern browsers 
continue to inch closer to consistently supporting the JavaScript (ECMAScript) 
standard. You can find details about the JavaScript core language syntax 
in Part III. 



IN THIS CHAPTER 



How to combine JavaScript 
with HTML 

How to accommodate 
different versions of 
JavaScript 

Language highlights for 
experienced programmers 



Combining JavaScript with HTML 

Scriptable browsers offer several ways to include scripts or scripted elements in 
your HTML documents. Not all approaches are recommended in today's best 
practices, but it's useful to learn even the old-school techniques so that you can 
understand legacy code when you come across it on the Web. 



<script> tags 



We marry JavaScript code to an HTML document using a 

< s c r i p t >< / s c r i p t > tag set that specifies the scripting language 



37 



Part I: Getting Started with JavaScript 



through the type attribute. You can have any number of such tag sets in your document. We recom- 
mend that all your scripts be external files linked to the HTML: 

<script type=" text/javascript" src="example.js"X/script> 

However, you can also embed JavaScript directly into the HTML by wrapping it in a 
<script>. . .</script> tag: 

<script type="text/javascript"> 
// JavaScript code goes here 
</scri pt> 

There are distinct advantages to linking external JavaScript to HTML rather than embedding the scripts 
directly in the markup. The principal of separation oj development layers encourages us to keep different 
aspects of a document apart, typically in separate, linked files. Doing so facilitates cleaner develop- 
ment, faster downloads, and more modular, re-purposable code that can be much easier to modify 
than mixtures of technologies cemented together in a single file. 

Linking to script libraries (.js files) 

The advantages of linking to external JavaScript files become immediately obvious when the same 
script needs to run on more than one page of a site. If the script were embedded in the HTML 
markup, each page would be bloated with redundant content, and modifying the script would 
necessitate repeating the same changes in more than one file. In contrast, linking to an external file 
adds only a single line to each HTML file, and the external JavaScript file can be modified just once to 
immediately affect every page that includes it. Another plus is that, by separating the script code from 
the HTML document, you will not have to worry about comment-hiding or CDATA section tricks (see 
below). 

Such an external script file contains nothing but JavaScript code — no <script> tags, no 
HTML. The script file you create must be a text-only file. Its filename extension can be anything, 
but the common convention is to use . j s . To instruct the browser to load the external file at 
a particular point in your regular HTML file, you add a src attribute to the <scri pt> tag 
as follows: 

<script type=" text/javascript" src="example.js"X/script> 

If you load more than one external library, you may include a series of these tag sets in the head of 
the document. 

Notice that the <script></script> tag pair is required, even though nothing appears between 
them. Don't put any script statements between the start and end tags when the start tag contains a 
src attribute. 

How you reference the source file in the src attribute depends on its physical location and your 
HTML coding style. In the preceding example, the . j s file is assumed to reside in the same direc- 
tory as the HTML file containing the tag. But you can just as easily link to JavaScript files located in 
other directories on your server or on other domains entirely. Just as with an HTML file, if you want 
to refer to an absolute URL, the protocol for the file is h 1 1 p : / / . 

<scri pt type="text/ javascri pt" src=". . /scripts /exampl e. js"X/script> 

<scri pt type=" text/ javascri pt" src="http : //www. exampl e . com/ exampl e .js" ></ script) 



38 



Chapter 4: JavaScript Essentials 



(A critical prerequisite for using script libraries with your documents is that your web 
server software must know how to map files with the . j s extension to a MIME type 
of appli cat ion/x- javascript. Test your web server and, if necessary, arrange for 
server configuration adjustments. It is rare that a modern server will not correctly recognize 
. js files.) 

When a user views the source of a page that links in an external script library, code from the 
. j s file does not appear in the window, even though the browser treats the loaded script 
as part of the current document. However, the name or URL of the . j s file is plainly visi- 
ble (displayed exactly as it appears in your source code). Anyone can open that file in their 
browser (using the http: / / protocol) to view the . js file's source code. In other words, an 
external JavaScript source file is no more hidden from view than JavaScript embedded directly 
in an HTML file. Nothing that your browser downloads to render a web page can be hidden 
from view. 

Specifying the MIME type & language 

Every opening <scri pt> tag should specify the type attribute, scri pt is a generic element indicat- 
ing that the contained statements are to be interpreted as executable script and not rendered as HTML. 
The element is designed to accommodate any scripting language that the browser knows — in other 
words, for which it contains an interpreter. For example, Internet Explorer carries interpreters for both 
JScript (Microsoft's version of JavaScript) and VBScript. 

<script type=" text/javascript" src="example.js"X/script> 
<script type="text/vbscri pt" src="exampl e . vb"X/scri pt> 

Both of these scripts will be interpreted by IE, but a non- VBScript-aware browser such as Mozilla will 
attempt to interpret only the JavaScript file. 

Specifying the language version 

It is rarely necessary to specify which version of JavaScript you wish to invoke in your 
documents. If your script relies on the objects and methods of a recent version of JavaScript 
that some older browsers won't support, it's better to test for that support directly. For example: 

// if this browser isn't DOM-aware, exit gracefully 
if (! document . getEl ementBy Id ) return; 

// now it's safe to use the DOM method 

var oExample = document . getEl ementById( "exampl e" ) ; 

However, it isn't always possible to test for the existence of language features at run-time. If the new 
feature is built into JavaScript's syntax, its mere presence in the script can stop the interpreter from 
compiling the script to the point where it can't even execute an lf-test. 

For example, take the E4X syntax introduced in JavaScript 1.6 (see Chapter 20, "E4X — Native XML 
Processing"): 

var xAuthor = <name> 

<first>George</first> 
<1 ast>Sand</l ast> 
</name> ; 



39 



Part I: Getting Started with JavaScript 



If you include this syntax in a script run by a browser that doesn't "know" E4X syntax, the 
script will simply not run, in some cases with no meaningful error message to alert the 
visitor or the developer. No code in the same script will run, even if it's within the abilities of 
the browser. 

You can isolate the new syntax with a version-specific type attribute for the scri pt element: 

<script src="exampl e-al 1 . js" type="text/ javascri pt"X/scri pt> 

<scri pt src="exampl e-1-6 . j s " type=" text/ javascri pt;version=1.6"X/script> 

or: 

<script type="text/javascript"> 

// script for all browsers goes here 
</scri pt> 

<script type=" text/ javascri pt; versi on=l . 6" > 

// script for browsers that know JavaScript 1.6 and later 
</scri pt> 

Be aware, though, that specifying the version as a special flag is non-standard so not all browsers sup- 
port it. In the specific case of E4X syntax, Mozilla has introduced another special flag for the type 
attribute: e4x=l meaning, essentially, "E4X support = true." 

<script src="example-e4x.js" type="text/javascript;e4x=l"X/script> 

The practical question then arises: If you have to wall off part of your script from older browsers, 
what alternative code do you give to those older browsers in place of the new code? And if you're 
writing that work-around code, why not let that be the only code? What advantage is there in writing 
the same logic in two different ways in the same script? It's a question to ponder when working with 
leading-edge language enhancements. 



The deprecated language attribute 

The type attribute is required for the <scri pt> tag as of HTML 4, formally published in 1998. 
Earlier browsers recognized the 1 anguage attribute instead of type. The 1 anguage attribute is 
deprecated, which means that it's an outdated feature of the language, has been replaced by newer 
constructs, and may become obsolete in future versions of HTML. Browsers continue to recognize it 
in order to support legacy web pages, but there's no reason to use it in industry-standard web sites 
today. We include it here so that you'll understand it when you encounter it in old markup. 

The 1 anguage attribute allowed the scrip ter to write for a specific minimum version of JavaScript 
or, in the case of Internet Explorer, other languages such as VBScript. For example, the JavaScript 
interpreter built into Navigator 3 knows the JavaScript 1.1 version of the language; Navigator 4 and 
Internet Explorer 4 include the JavaScript 1.2 version. For versions beyond the original JavaScript, you 
could specify the language version by appending the version number after the language name without 
any spaces, as in: 

<script 1 anguage=" JavaScri ptl . 1 "> . . .</script> 

<script language=" JavaScri ptl. 2 ">. . .</script> 

The type attribute didn't gain browser support until Internet Explorer 5, Mozilla, and W3C 
DOM-compatible browsers. If you need to inform even older browsers which language and 



40 



Chapter 4: JavaScript Essentials 



version of scripting you're using, you can specify both the type and 1 anguage attributes in your 
<scri pt> tags, as older browsers will ignore the type attribute: 

<script type=" text/javascript" language="JavaScriptl.5">. . .</script> 

Of course, if you're depending on features in JavaScript 1.5, you've forgone legacy browsers 
anyway. In this case, just take the forward-looking approach and test for modern methods at the 
beginning of the script. 

The proprietary for and event attributes 

Internet Explorer versions 4 through 7 offered a variation on the <scri pt> tag that bound 
statements of a script to a specific object and an event generated by that object. In addition to 
the 1 anguage attribute, the tag must include both for and event attributes (not part of the 
HTML specification). The value assigned to the for attribute was a reference to the desired 
object. Most often, this was simply the identifier assigned to the object's id attribute. The event 
attribute was the event handler name that you wanted the script to respond to. For example, if you 
designed a script to perform some action upon a mousedown event in a paragraph whose ID was 
my Paragraph, the script statements were enclosed in the following tag set: 

<script f or="myParagraph" event="onmousedown" type=" text/ j avascr i pt " > 

</script> 

Statements inside the tag set executed only upon the firing of the event. No function definitions were 
required. 

Because the for and event attributes were proprietary creations of Microsoft, this way of binding 
an object's event to a script guaranteed that only Internet Explorer would execute the script when the 
named event occurred. 

Even in its day, the scri pt for tag was not a winner. Its attributes constituted a lot of source 
code overhead for each object's script, so it was never a very efficient technique for linking script 
statements to multiple objects and events. In addition, non-Internet Explorer and pre-Internet 
Explorer 4 browsers would execute the script statements as the page loaded, making this 
proprietary language feature impractical in any cross-browser script. 

Old-school inline JavaScript 

Back in the bad old days of "tag soup" web development, it was common practice to insert JavaScript 
statements right in the HTML markup: 

<select id="nations" name=" nati ons " onchange="doSomethi ng(thi s ) ; "> 

In that example, the change event for the control object nations is set to trigger the JavaScript 
statements provided: a custom function call. We'll show you how this works elsewhere in the 
book to help you read legacy code, but combining markup and scripting like that today is 
commonly considered to be "very '90s." 

There are many disadvantages to inserting JavaScript into markup this way: it's awkward and 
expensive to change the markup or the scripting independently when they're this intermeshed; 
the downloaded markup is unnecessarily bloated and doesn't take full advantage of the centralized 



41 



Part I: Getting Started with JavaScript 



modularity of externally linked scripts; and user agents running versions of JavaScript that can't 
handle the code are unable to avoid the script. 

In a modem page, this markup would be cleaned up to 

<select id="nations" name=" nati ons " > 
with the event handler assigned entirely in JavaScript with something like 

AddEvent( "nati ons" , "change", doSomethi ng ) ; 

where the AddEvent( ) function can cater to a variety of event models in different browsers, can 
be entirely separate from the markup to protect user agents that can't handle scripting, and 
can be firewalled by defensive if-tests to protect it from legacy JavaScript interpreters that don't play 
well with modem code. 



Accommodating the JavaScript-incapable user agent 

There are several categories of user agent that can't or don't support JavaScript, representing, by some 
accounts, some ten to fifteen percent of all internet usage today. These user agents include search 
engine spiders, mobile device browsers, browsers inside government and corporate firewalls that strip 
out script for security reasons, assistive technologies, and browsers in which, for any of a variety of 
reasons, their users have turned scripting off. There is sure to be a small number of legacy browsers 
still in use today that cannot ran JavaScript or that support very early versions, but the vast majority 
of non-JavaScript-using internet visitors are using contemporary hardware and software. 

It is our responsibility as web developers to acknowledge that JavaScript is an option, not a 
given, and to ensure that our pages are functional even in its absence. It's our mission to use 
JavaScript to enhance the visitor's experience and not to supply critical elements without which 
a page would be broken or dead in the water. We make sure that the HTML markup pro- 
vides all the fundamental content, hyperlinks, and form fields, and that server-side scripting 
completes the dialog between client and server that is the core of the HTTP request model. 
Then, when JavaScript is running, it can morph the page, pretty up the user interface, and quicken 
the response time. That is the win- win model of modem web scripting. 

The question then comes, how can we add JavaScript to an HTML document in a way that leaves the 
page fully functional when the script interpreter is not running, not present, or packing an obsolete 
version? Our tactics are several: 

• We begin our scripts by testing for the presence of modem DOM methods such as doc- 
ument . getEl ementBy Id in order to turn away obsolete versions of the JavaScript 
interpreter. 

• We export JavaScript to external files and link them to the HTML document with script tags . 
User agents not running a scripting interpreter won't even go there. 

• Corollary to the above, we omit JavaScript from event attributes in HTML tags, and instead use 
JavaScript to assign event handlers to page elements. 

• If it is ever unavoidable to include JavaScript in the HTML document itself, enclose the script in 
HTML comments so that it won't be rendered by not-script-sawy browsers. 

Let's take a moment to expand on that last point. 



42 



Chapter 4: JavaScript Essentials 



Commenting out script in HTML 

Non-scriptable browsers do not know about the <script> tag. Normally, browsers ignore 
tags that they don't understand. That's fine when a tag is just one line of HTML, but a 
<script>. . .</script> tag pair can enclose any number of script statement lines. Old and 
compact browsers don't know to expect a closing </scri pt> tag. Therefore, their natural inclination 
is to render any lines they encounter after the opening < s c r i p t > tag. Seeing JavaScript code spilling 
out onto a page is sure to confuse or erode the confidence of any visitor. 

You can, however, exercise a technique that tricks most non-scriptable browsers into ignoring 
the script statements: surround the script statements (inside the <scri pt> tag set) with HTML 
comment markers. An HTML comment begins with the sequence < ! — and ends with — >. 
Therefore, you should embed these comment sequences in your scripts according to the 
following format: 

<script type="text/javascript"> 

<!-- 

script statements here 

//--> 

</script> 

JavaScript interpreters know to ignore a line that begins with the HTML beginning comment sequence 
< ! - -, but they need a little help with the ending sequence. The close of the HTML comment starts 
with a JavaScript comment sequence ( / / ). This tells JavaScript to ignore the line; but a non-scriptable 
browser sees the ending HTML symbols and begins rendering the page with the next HTML tag or 
other text in the document. An older browser doesn't know what the </scri pt> tag is, so the tag is 
ignored and rendering resumes after that. 

Commenting out script in XHTML as character data 

If your document is marked up with XHTML, the comment syntax is significantly different: 

<script type="text/javascript"> 
<!--//--><![CDATA[//><!— 

// script statements here 
//--><!]]> 
</script> 

That's quite a mouthful and deserves a bit of explanation. 

XHTML parsers are intolerant of < symbols that don't begin elements and & symbols that don't begin 
HTML entities, yet these characters are commonplace JavaScript operators. The solution is to encase 
your script statements in what is known as a CDATA (pronounced "see-day-tah") section: 

<! [CDATAf 

XHTML permits any character here including < and & 

]]> 

We can then add the HTML comment markers to stop legacy browsers from rendering the 
script: 

<script type="text/javascript"> 
<!--<! [CDATAf 



43 



Part I: Getting Started with JavaScript 



// script statements here 
//--]]> 
</scri pt> 

However, we can't stop here because XHTML also obeys the < ! - - and - - > comment tags and an 
XHTML-aware browser will ignore the CDATA section and not execute the script. So, we have to close 
the comment tag before the CDATA begins in order to satisfy XHTML: 

<!-- --><![CDATA[ 
and use // comment syntax to make most HTML parsers ignore the rest of that line: 

<!--//--><! [CDATA[ 

Some HTML parsers will treat the line after / / as a comment and others will close the comment area 
with -->, so we have to make the CDATA open-tag not show up. The technique we're using is to 
make the HTML parsers think it's a closed tag 

<! [CDATA[> 

but to keep XHTML from considering it closed we'll add another comment marker 
<! [CDATA[//> 

and open the block comment tag once more to stop some browsers from attempting to render the 
JavaScript code as plain text: 

<!--//--><! [CDATA[//><! - 
Finally, the CDATA close-tag is commented out for HTML parsers: 

//--]]> 

Whew! That's some of the fun web developers get to have when making multiple standards play nicely 
with one another. How much cleaner to simply export the JavaScript to an external file! 

The noscript tag 

The noscript element is the converse of s c r i p t . A JavaScript-aware browser will render the con- 
tents of the noscript block if scripting has been turned off or if the browser doesn't support a 
scripting language invoked by a script element in the document. (Significantly, a legacy browser 
that doesn't support scripting at all and doesn't recognize script-related tags will likewise render the 
contents of both script and noser i pt blocks, which is why we comment out the contents of a 
scri pt block. A noser i pt block will therefore be rendered by all browsers when scripting is not 
supported.) 

You can display any standard HTML within the noscri pt tag set. It is a block-level element that can 
contain paragraphs, lists, divisions, headings, and so on. 

The conventional use of noscri pt is to present HTML content to display in the absence of 
scripting support — a message such as, "This page would be more interesting if viewed with 
JavaScript running," for example, or an HTML hyperlink to a page that provides content that would 
otherwise be inserted by Javascript. 



44 



Chapter 4: JavaScript Essentials 



That use of noser i pt has commonly been superseded in recent years by the practice of providing 
only the non-scripting markup in the HTML, then replacing or enhancing that structure with script- 
ing. Rather than telling visitors that they ought to upgrade their browsers or turn on scripting, we 
begin with the assumption that they're looking at our pages with a user agent that they need or want 
to use and give them decent, functional pages; then use scripting to give JavaScript-capable browsers 
a nicer page. It seems unlikely that there is anyone today using a browser with scripting deliberately 
turned off, or running behind a corporate firewall that strips out scripting, or using a mobile device 
with no scripting support, who isn't aware of the additional delights that the internet has to offer with 
the help of JavaScript. An admonition to upgrade may have been useful advice back in the '90s, but 
today it seems condescending and redundant. 

Listing 4-1 is an example of presenting different content to scriptable and non-scriptable browsers. 
The HTML includes a plain paragraph that everyone will see and another inside a noser i pt ele- 
ment that will only be seen by user agents that don't support scripting, have JavaScript turned off, or 
are running an old JavaScript interpreter that's not DOM-aware. The accompanying JavaScript inserts 
another paragraph that will only be revealed by user agents with running JavaScript interpreters that 
are aware of the W3C DOM methods appendChild( ) and createTextNode( ). 



LISTING 4-1 



Presenting Different Content for Scriptable and Nonscriptable Browsers 

HTML: jsb-04-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<ti tl e>Presenti ng Different Content for Scriptable and 
Nonscriptable Browsers</ti tl e> 

<script type=" text/javascript" src="../jsb-global . js"X/script> 
<script type=" text/javascript" src="jsb-04-01.js"X/script> 

</head> 

<body> 

<hl>Presenti ng Different Content for Scriptable and Nonscriptable 
Browsers</hl> 

< p > T h i s text will be revealed to everyone . </p> 
<noscript> 

<p>0nly user agents that don't or can't support W3C DOM 
scripting will reveal this text.</p> 
</noscript> 

</body> 
</html > 

continued 



45 



Part I: Getting Started with JavaScript 



LISTING 4-1 



(continued) 



JavaScript: jsb-04-01.js 

// initialize when the page has loaded 
addEvent ( wi ndow , 'load', addText); 

f uncti on addText ( ) 

{ 

// ensure a DOM-aware user agent 

if (! document . appendChi 1 d || ! document . createTextNode ) return; 
// create a text node 

var oNewText = document . createTextNode( "Only DOM-aware user agents <J 
running JavaScript will reveal this text."); 

// create a paragraph 

var oParagraph = document . createEl ement (' p ') ; 

// insert the text into the paragraph 
oParagraph. appendChild( oNewText ) ; 

// insert the paragraph at the end of the document 
document. bo dy.appendChild(oParagraph); 



Hiding scripts (not!) 



A common question from beginning JavaScript programmers is how to hide scripts from 
visitors to a page, perhaps to protect a cherished bit of clever code. The short answer is that 
this isn't possible. In order to run, client-side JavaScript must be downloaded with the page, and 
therefore is visible in the browser's source view. The URL for an external linked script can simply be 
pasted into a browser's address bar. 

If you are worried about other scripters stealing your scripts, you could include a copyright notice 
in your source code. Not only are your scripts visible to the world, but so are a thiefs scripts. This 
way, you can easily see when someone lifts your scripts verbatim. Of course, there's nothing stopping 
someone from copying your script and deleting the notice of ownership. 

The most you can hope for along these lines is to obfuscate your code, or make it difficult, 
time-consuming, and tiresome for a human to read. Obfuscation techniques include removing 
carriage returns and unnecessary spaces and tabs, using meaningless function and variable names, 
using variables to hold commonly named objects, using Boolean logic in place of i f and other 
syntactical branching, writing self-generating code, using recursion, fragmenting logic sequences into 
multiple nested function calls, and encoding text in decimal, hexadecimal, or octal expressions. At 
the end of the day, however, global-replacement, careful reading, and patience can expose the logic 
of any text-based script. The most productive use of a JavaScript obfuscator is simply to produce 
a "compressed" copy of a script using as few characters as possible for fast download of enormous 
scripts. However, even that use is questionable since external scripts are cached by the browser after 
the first download. 



46 



Chapter 4: JavaScript Essentials 



If keeping your source code private is a great concern, consider using another programming 
language that compiles to machine code. Because of the existence of disassemblers that turn machine 
language back into source code, compiling can be viewed as just another form of obfuscation, but it 
will certainly reduce the number of people willing to put effort into decoding it. 

However, it's nearly impossible to conceal anything significant. Even if they can't read your script, 
good programmers can look at the way your software behaves and write a fresh script that accom- 
plishes much the same thing. The time you take to try to conceal your script could be spent writing 
new, exciting code! 

We suggest that you consider flipping the paradigm on its head. Instead of attempting to conceal your 
programming code, flaunt it! Add helpful comments to the source code, publish it on your blog and on 
programming web sites, and otherwise assist as many people as possible to learn about and use it. (Add 
a Creative Commons license to encourage people to copy your code and keep it free for public use.) 
If you gain a reputation as a clever and helpful programmer, people will come to you for more. 

Scripting for different browsers 

Cross-browser compatibility is a concern for every JavaScript programmer. Even though the most 
recent browsers are doing a decent job of providing a workable lowest common denominator 
of scriptability, you will still have to consider a range of JavaScript support, from the most advanced 
browser to the least. Even the differences between the latest Firefox and the latest Internet Explorer 
are significant. Planning for compatibility begins with deciding on your goals for various classes of 
user agent. 

Building the foundation beneath the towers 

The purpose of most web pages can be boiled down to "delivering particular content." Where one web 
site differs from another is the specific content being delivered and its "look and feel" — the graphic 
appearance of the page and the style of the user interface with which visitors request further information. 

The principal of progressive enhancement guides us first to deliver the content from the server to the 
client in HTML markup, without relying on JavaScript for core functionality. A web site should be 
fully usable and navigable, with all its public content exposed to all user agents, including those that 
don't support scripting . . . such as search engines! After that, we use JavaScript to enhance the visitor's 
experience and make it faster, easier, more attractive, or more fun in browsers with JavaScript enabled. 

One of the consequences of considering JavaScript last instead of first in the planning process is that 
we'll often discover that much of a web site's functionality that we might have expected to hand over 
to JavaScript is instead handled perfectly well by other, more universally supported technologies. We 
should ask JavaScript to perform only those functions that are outside the reach of core browser func- 
tionality such as HTML rendering and CSS styling. For example, navigation links should be marked 
up as functional hyperlinks regardless of whether JavaScript adds any spice to the mix. Multi-level 
menus, pop-up dialogs, and roll-over image changes can often be implemented using just HTML and 
CSS, and therefore work for a broader audience. 

Ajax (Asynchronous JavaScript and XML) is an interesting case in point. Often developers and even 
clients will choose Ajax to deliver content just because it's perceived to be sexy technology, but with- 
out pausing to consider whether it's really more useful, faster, or more effective than normal page 
navigation. Reading content from the server takes a certain amount of time regardless; if all the images 
on a page are already downloaded and therefore cached, it's only the HTML markup that will be the 
overhead of reading a new page, and that can be the smallest slice of a page. Navigating to indi- 
vidual pages to reveal different content means that visitors can easily bookmark and share links to 



47 



Part I: Getting Started with JavaScript 



specific chunks of content, which isn't normally true of Ajax-retrieved content. Just because we can 
use JavaScript for a particular purpose doesn't mean we have to or should. 

Once the core page or site is planned in detail using server-side technologies and HTMI7CSS down- 
loads, we can plot out the remainder of the user interface with JavaScript — the sweet dessert that 
follows the entree! 

JavaScript can be used to add animation to an otherwise static presentation, replace a navigation link with 
an Ajax download of additional content, augment a button-click editing process with drag-and-drop, 
fancify a form, and so on. While adding these nice-to-haves, make sure that all the content you're 
providing through JavaScript is also accessible without scripting. If you find yourself adding critical 
content to the site that can only been retrieved using JavaScript, you know that you've gone too far. 
Step back, add the new content to the core web site, then resume your JavaScript planning. 

Choosing your battles 

Any public web site can, and ultimately will, be viewed using every sort of user agent in existence. 
Because the range of JavaScript support is so broad — ranging from Early Primitive to Leading 
Edge — it can be quite challenging, verging on impossible, to write for every browser that's got a 
JavaScript interpreter. Part of web development planning can therefore be viewed as 'choosing your 
battles' or a kind of triage — drawing the line between interpreters you'll support and those you 
won't, and language features you'll use and those you'll avoid. According to this approach, instead of 
spending time trying to write script that will run in ancient browsers, simply block them from the 
playing field and focus your attention on developing code for the modern ones. 

If, as we recommend, you've engineered your site so that all the core content and functionality are 
provided by HTML delivered from the server, you won't have to feel negligent if you prevent legacy 
browsers from trying to run your script. Relax — everyone will be able to use your site. By limiting 
the JavaScript interpreters you support to the current crop of modern ones and shutting out the older 
ones, you can save yourself hours of painstaking development work for a small minority of visitors, a 
decision that can salvage your deadline, your budget, and your sanity. 

For example, most of the scripts in this book begin with the simple if-test 

if (! document . getEl ementBy Id ) return; 

In other words, "if the JavaScript interpreter running in this browser does not know about the 
getEl ementBy Id method of the document object, stop running this script." This one state- 
ment shuts out interpreters that are too old to know about modem Document Object Model 
methods, allowing you to write most of your code for a single audience. At the other end of the 
spectrum, you may wish to avoid, for now, using leading-edge JavaScript syntax such as E4X 
that will stop most current browsers cold in their tracks. The middle ground — ECMAScript 3- 
and W3C DOM2-aware browsers — constitutes the vast majority in use today, and presents a very 
comfortable compromise with relatively consistent language support. 

In planning your application or web site, it makes far more sense to deliver a single stream of 
content that can be viewed through all user agents rather than duplicating content in different 
modes. The latter approach was sometimes used in years past, for a site using frames and a parallel 
no-frames version, for example. In case you have a notion of creating an application or site that 
has multiple paths for viewing the same content, don't forget that maintenance chores lie ahead 
as the site evolves. Will you have the time, budget, and inclination to keep all paths up to date? 
Despite whatever good intentions a designer of a new web site may have, in our experience, 
the likelihood that a site will be maintained properly diminishes rapidly with the complexity of the 
maintenance task. 



48 



Chapter 4: JavaScript Essentials 



That said, providing multiple channels does not necessarily mean a duplication of effort. A site may be 
marked up to navigate to separate pages to deliver different content, but when scripting is supported 
the site could deliver the same content using Ajax. Since both apparent channels of content come from 
the server, we could use Ajax to request the same data stream that each stand-alone page requests. 
When the data is changed on the server, say, by modifying text in a database, both the stand-alone 
page and the Ajax content injection change accordingly. 

Object detection 

The methodology of choice by far for implementing browser version branching is object 
detection. The principle is simple: If an object type exists in the browser's object model, it 
is safe to execute script statements that work with that object. 

One example of object detection that you'll see in a lot of older scripts uses the i mages collec- 
tion. A script can change the src attribute of an image — effectively replacing it with another 
image read from the server — only if the version of JavaScript running in the browser recognizes 
images as objects. Object models that implement images always include an array of image objects 
belonging to the document object. The document . i mages array always exists, even with a 
length of zero when no images are on the page. Therefore, if you wrap the image-swapping 
statements inside an i f construction that lets browsers pass only if the document, images array 
exists, older browsers simply skip the statements: 

function i mageSwap ( i mgName , url ) 
{ 

if ( document . i mages ) 
{ 

document . i mages [ i mgName] . s rc = url; 

} 

} 

Object detection works best when you use it to test for the same object you need to use. It can get 
you into trouble when you use it to make assumptions about browser version and support for lan- 
guage features other than the one being tested. 

For example, Internet Explorer 4 introduced a document object array called document .all, 
which is used very frequently in building references to HTML element objects. Netscape 
Navigator 4, however, did not implement that array; instead, it had a document-level array object 
called 1 ayers, which was not implemented in Internet Explorer 4. Unfortunately, many scripters 
used the existence of these array objects not as prerequisites for addressing those objects, but as 
determinants for the browser version. They set global variables signifying a minimum version of 
Internet Explorer 4 if document. all existed and Netscape Navigator 4 if document. layers 
existed. This was dangerous because there was no way of knowing whether a future version of 
a browser might adopt the object of the other browser brand or eliminate a language feature. 
In fact, when the Mozilla-based Netscape version first arrived, it did indeed remove all the 
layers stuff, replacing it with W3C standards-based features. Tons of scripts on the web used 
the existence of document. layers to branch to Netscape-friendly code that didn't even use 
document . 1 ayers. Thus, visitors using Netscape 6 or 7 found that scripts either broke or didn't 
work, even though the browsers were more than capable of doing the job. 

This is why we recommend object detection, not for browser version sniffing, but for object availabil- 
ity branching, as previously shown for images. Moreover, it is safest to implement object detection 
only when all major browser brands (and the W3C DOM recommendation) have adopted the object 
so that behavior is predictable wherever your page loads in the future. 



49 



Part I: Getting Started with JavaScript 



Techniques for object detection include testing for the availability of an object's method. 
A reference to an object's method returns a value, so such a reference can be used in a conditional 
statement. For example, the following code fragment demonstrates how a function can receive an 
argument containing the string ID of an element and convert the string to a valid object reference for 
three different DOMs: 

function myFunc(elemlD) 

{ 

va r ob j ; 

if (document . getEl 

{ 

obj = document. 

) 

else if (document. 

{ 

obj = document. 

1 

else if (document. 

( 

obj = document. 

1 

if (obj) 

( 

// statements that work on the object 

1 

} 

With this object detection scheme, it doesn't matter which browser brand, version, or operating sys- 
tem support a particular way of changing an element ID to an object reference. Whichever document 
object property or method is supported by the browser (or the first one, if the browser supports more 
than one), that is the property or method used to accomplish the conversion. If the browser supports 
none of them, no further statements execute in this function. Keep in mind, however, that the first 
approach in this example is sufficient (and recommended) as the technique for obtaining all objects 
from an ID in modern browsers. 

If your script wants to check for the existence of an object's property or method, you may also 
have to check for the existence of the object beforehand, if that object is not part of all browsers' 
object models. An attempt to reference a property of a nonexistent object in a conditional 
expression generates a script error. To prevent the error, you can cascade the conditional tests 
with the help of the && operator. The following fragment tests for the existence of both the 
document . body object and the document . body . styl e property: 

if ( document . body && document . body . sty 1 e ) 

{ 

// statements that work on the body's style property 

} 

This is the functional equivalent of: 

if ( document . body ) 

{ 



ementBy Id ) 

getEl ementById(el emID) ; 
al 1 ) 

al 1 (el emID) ; 
1 ayers ) 

1 ayersfel emID] ; 



50 



Chapter 4: JavaScript Essentials 



if ( document . body . sty 1 e ) 
{ 

// statements that work on the body's style property 

} 

} 

In both examples, if the test for document . body fails, JavaScript bypasses the second test. 

One potential "gotcha" in using conditional expressions to test for the existence of an object's 
property is that if the property exists, but its value is zero or an empty string, the conditional 
test responds the same as it would if the property did not exist. To work around this poten- 
tial problem, the conditional expression can examine the data type of the value to ensure 
that the property genuinely exists. A nonexistent property for an object reports a data type of 
undefined. Use the type of operator (discussed in Chapter 22, "JavaScript Operators") to test for a 
valid property: 

if ( document . body && typeof document . body . scrol 1 != "undefined") 
{ 

// statements that work on the body's scroll property 

) 

We wholeheartedly recommend designing your scripts to take advantage of object detection in 
lieu of branching on particular browser name strings and version numbers. Scriptable features 
are gradually finding their way into browsers embedded in a wide range of nontraditional com- 
puting devices. These browsers may not go by the same names and numbering systems that 
we know today, yet such browsers may be able to interpret your scripts. By testing for browser 
functionality, your scripts will likely require less maintenance in the future. 

Browser version detection 

Years ago, before object detection caught on, the commonplace way to pilot a script through the rocky 
shoals of language support was browser sniffing. As described more fully in Chapter 42, "The Navigator 
and Other Environment Objects," your scripts can examine the navigator object to discover which 
make and model the current browser claims to be. After examining the browser's purported name and 
version number, a script can branch to different bits of logic specific to the various browsers available 
at the time. We don't use this technique any more, chiefly because browsers can and do lie about 
what they are, because browser version sniffing isn't future-proof, and because it's a hack — it tests 
for one thing in order to act on another. 

Browser sniffing is like letting someone fly a jet because they say they're a pilot. They might 
not actually be a pilot just because they claim to be, and even if they are, they might have 
gotten their pilot's license before jets were invented. In contrast, with object detection, you find out if 
they know how to fly the particular aircraft at hand and you let them fly it only if they can — simple, 
direct, and foolproof. 



Designing for Compatibility 

Each new major release of a browser brings compatibility problems for page authors. It's not 
so much that old scripts break in the new versions (well-written scripts rarely break in new 
versions). The problems center on the new features that attract designers when the designers 



51 



Part I: Getting Started with JavaScript 



forget to accommodate visitors who have not yet advanced to the latest and greatest browser version 
or who don't share your browser brand preference. 

Catering only to the lowest common denominator can more than double your development time, due 
to the expanded testing matrix necessary to ensure a good working page in all operating systems and 
on all versions. Decide how important the scripted functionality you employ in a page is for every 
user. If you want some functionality that works only in a later browser, you may have to be a bit 
autocratic in defining the minimum browser for scripted access to your page; any lesser browser gets 
shunted to a simpler presentation of your site's data. 

Another possibility is to make a portion of the site accessible to most, if not all, browsers, and restrict 
the scripting to the occasional enhancement that non-scriptable browser users won't miss. When the 
application reaches a certain point in the navigation flow, the user needs a more capable browser 
to get to the really good stuff. This kind of design is a carefully planned strategy that lets the site 
welcome all users up to a point, but then enables the application to shine for users of, say, W3C 
DOM-compatible browsers. 

The ideal page is one that displays useful content in any browser but whose scripting enhances the 
experience of the page visitor — perhaps by offering more efficient site navigation or interactivity with 
the page's content. That is certainly a worthy goal to aspire to. But even if you can achieve this ideal 
on only some pages, you will reduce the need for defining entirely separate, difficult-to-maintain paths 
for browsers of varying capabilities. 

Regardless of your specific browser compatibility strategy, the good news is that time tends to mini- 
mize the problem. Web standards have solidified greatly in the past few years, and browser vendors 
have made significant strides toward fully supporting those standards. 



Dealing with beta browsers 

If you have crafted a skillfully scripted web page or site, you may be concerned when a prerelease 
(or beta) version of a browser available to the public causes script errors or other compatibility prob- 
lems to appear on your page. Do yourself a favor: Don't overreact to bugs and errors that occur in 
prerelease browser versions. If your code is well written, it should work with any new generation of 
browser. If the code doesn't work correctly, consider the browser to be buggy. Report the bug (prefer- 
ably with a simplified test-case script sample) to the browser maker. 

One exception to the "it's a beta bug" rule arose in the transition from Netscape Navigator 4 to the 
Mozilla engine (first released as Netscape Navigator 6). A conscious effort to eliminate a proprietary 
Netscape Navigator 4 feature (the <1 ayer> tag and corresponding scriptable object) caused many 
Netscape Navigator 4 scripts to break on Mozl betas (and final release). Had scripters reported the 
problem to the new browsers' developer (Mozilla), they would have learned about the policy change 
and planned for the new implementation. It is extremely rare for a browser to eliminate a popular 
feature so quickly, but it can happen. Stronger web standards have probably minimized the chances 
of this situation happening again any time soon. 

It is often difficult to prevent yourself from getting caught up in a browser maker's enthusiasm for a 
new release. But remember that a prerelease version is not a shipping version. Users who visit your 
page with prerelease browsers should know that there may be bugs in the browser. That your code 
does not work with a prerelease version is not a sin; neither is it worth losing sleep over. Just be sure 
to connect with the browser's maker either to find out whether the problem will continue in the final 
release or to report the bug so that the problem doesn't make it into the release version. 



52 



Chapter 4: JavaScript Essentials 



Compatibility ratings in reference chapters 

With the proliferation of scriptable browser versions since Navigator 2, it is important to know up 
front whether a particular language or object model, property, method, or event handler is supported 
in the lowest common denominator for which you are designing. Therefore, in this book, we include 
frequent compatibility ratings, such as the following example: 

Compatibility: WinIE5+, MacIE5+, NN4+, Moz+, Safari+, Opera+, Chrome+ 

A plus sign after a browser version number means that the language feature was first implemented in 
the numbered version and continues to be supported in succeeding versions. A minus sign means that 
the feature is not supported in that browser. The browsers tested for compatibility include Internet 
Explorer for Windows and Macintosh, Netscape Navigator, Mozilla (including all browsers based on 
the Mozilla engine), Apple Safari, Opera, and Google Chrome. We also recommend that you print the 
JavaScript and Browser Object Quick Reference file shown in Appendix A. The file is on the compan- 
ion CD-ROM in PDF format. This quick reference clearly shows each object's properties, methods, and 
event handlers, along with keys to the browser version in which each language item is supported. You 
should find the printout to be valuable as a day-to-day resource. 

This is a great place to clarify what we mean by "all browsers based on the Mozilla engine." Once 
upon a time, Mozilla pretty much meant Netscape, but those days are long gone. Now there are sev- 
eral viable Mozilla-based browsers that fall under the Moz+ designation in the compatibility charts 
throughout this book, including Netscape, Firefox, Camino, SeaMonkey, Flock, and others. 

Here we're using "Mozilla" to refer to the Gecko (nee NGLayout) layout engine. The numbering sys- 
tems of the individual browser brands are not synchronized to the underlying Mozilla engine versions, 
making it difficult to know exactly which browser supports what feature. The following table shows 
which individual browser brands and versions correspond to the Mozilla engine numbering system: 



Mozilla 


Netscape 


Firefox Camino 


ml8 


6.0 




0.9.2 


6.1 




0.9.4 


6.2 




1.0.1 


7.0 




1.2b 




0.1 


1.3a 




0.5 


1.4 


7.1 




1.5 




0.7 


1.7 




1.0 


1.7.2 


7.2 




1.7.5 


8.0-8.1 




1.8 




1.5 1.0 


1.8.1 


9.0 


2.0 1.6.5 



53 



Part I: Getting Started with JavaScript 



Mozilla 


Netscape 


Firefox 


Camino 


1.9 




3.0 


2.0 


1.9.1 




3.5 




1.9.2 




3.6 




1.9.3 




3.7 




2.0 




4.0 





As you can see, Netscape 6.0 and 6.2 were based on Mozilla versions of less than 1. It is rare to see 
either of these versions "in the wild" these days. The focus, therefore, is on Mozl and later. Thus, the 
compatibility charts use Mozl as the baseline feature set. 

In summary, when you see Moz+ in the compatibility charts, it ultimately resolves to Netscape 7 or 
later, Firefox 1 or later, and Camino 1 or later, to name the most popular Mozilla-based browsers 
currently in use. 

Language Essentials for Experienced 
Programmers 

In this section, experienced programmers can read the highlights about the core JavaScript 
language in terms that may not make complete sense to those with limited or no scripting 
experience. Here, then, is the quick tour of the essential issues surrounding the core JavaScript 
language: 

• JavaScript is a scripting language. The language is intended for use in an existing host envi- 
ronment (for example, a web browser) that exposes objects whose properties and behaviors are 
controllable via statements written in the language. Scripts execute within the context of the 
host environment. The host environment controls which, if any, external environmental objects 
may be addressed by language statements running in the host environment. For security and 
privacy reasons, web browsers generally afford little or no direct access through JavaScript to 
browser preferences, the operating system, or other programs beyond the scope of the browser. 
The exception to this rule is that modern browsers allow deeper client access (with the user's 
permission) through trust mechanisms such as signed scripts (Mozilla) or trusted ActiveX con- 
trols (Microsoft). 

• JavaScript is object based. Although JavaScript exhibits many syntactic parallels with 
the Java language, JavaScript is not as pervasively object-oriented as Java. The core 
language includes several built-in static objects from which working objects are generated. 
Objects are created through a call to a constructor function for any of the built-in objects 
plus the new operator. For example, the following expression generates a String object and 
returns a reference to that object: 

new St ri ng ( " Hel 1 o" ) ; 

Table 4-1 lists the built-in objects with which scripters come into contact. 



54 



Chapter 4: JavaScript Essentials 



TABLE 4-1 





JavaScript Built-in 


Objects 




Core Objects 


Error Objects 


XML Objects 


JSON Object 


Array' 


Error 2 


Namespace 4 


JSON 5 


Bool ean 


Eval Error 2 


QName 4 




Date 


RangeError 2 


XML 4 




Functi on 1 


Ref erenceError 2 


XMLList 4 




Global 


SyntaxError 2 






Math 


TypeError 2 






Number 1 


URIError 2 






Object 1 


Reg Exp 3 


St r i ng 1 



'Although defined in ECMA Level 1, was first available in NN3 and IE3/J2. 

2 Defined in ECMA Level 3; implemented in Moz1. 

3 Defined in ECMA Level 3; implemented fully in NN4 and 1E6. 

4 Defined in E4X; implemented in Mozilla 1.8.1 (Firefox 2.0). 

'Defined in ECMA Level 5; implemented in Mozilla 1.9.1 (Firefox 3.5). 



• JavaScript is loosely typed. Variables, arrays, and function return values are not denned to be 
of any particular data type. In fact, an initialized variable can hold different data type values in 
subsequent script statements (obviously not good practice but possible nonetheless). Similarly, 
an array may contain values of multiple types. The range of built-in data types is intentionally 
limited: 

• Boolean (true or fal se) 

• Null 

• Number (double-precision 64-bit format IEEE 734 value) 

• Object (encompassing the Array object) 

• String 

• Undefined 

• XML (in E4X) 

• The host environment defines global scope. Web browsers traditionally define a browser 
window or frame to be the global context for script statements. When a document unloads, all 
global variables defined by that document are destroyed. 

• JavaScript variables have either global or local scope. A global variable is initialized in 

v a r statements outside of all functions. In a web browser, it typically executes as the document 
loads. All statements in that document can read or write that global variable. A local variable is 
also initialized with the v a r operator but inside a function. Only statements inside that function 
may access that local variable. 



55 



Part I: Getting Started with JavaScript 



• Scripts sometimes access JavaScript static object properties and methods. Some 
static objects encourage direct access to their properties or methods. For example, all 
properties of the Math object act as constant values (for example, Math . P I). 

• You can add properties or methods to working objects at will. To add a property to an 
object, simply assign a value of any type to it. For example, to add an author property to a 
string object named myText, use: 

myText . author = "Jane"; 

Assign a function reference to an object property to give that object a new method: 

// function definition 
function doSpecial(argl) 
1 

// statements 

) 

II assign function reference to method name 
myObj . handl eSpeci al = doSpecial; 

// invoke method 
myObj.handleSpecial (argValue) ; 

Inside the function definition, the this keyword refers to the object that owns the method. 

• JavaScript objects employ prototype-based inheritance. All object constructors create 
working objects whose properties and methods inherit the properties and methods defined for 
the prototype of that object. Scripts can add and delete custom properties and methods associ- 
ated with the static object's prototype so that new working objects inherit the current state of 
the prototype. Scripts can freely override prototype property values or assign different functions 
to prototype methods in a working object without affecting the static object prototype. But if 
inherited properties or methods are not modified in the current working object, any changes to 
the static object's prototype are reflected in the working object. (The mechanism is that a refer- 
ence to an object's property works its way up the prototype inheritance chain to find a match to 
the property name.) 

• JavaScript includes a large set of operators. You can find most operators that you are accus- 
tomed to working with in other languages. 

• JavaScript provides typical control structures. All versions of JavaScript offer i f , 

if. . .el se, for, and whi 1 e constructions. JavaScript 1.2 (NN4+, IE4+, and all modern 
mainstream browsers) added do while and switch constructions. Iteration constructions 
provide break and continue statements to modify control structure execution. 

• JavaScript functions may or may not return a value. There is only one kind of JavaScript 
function. A value is returned only if the function includes a return keyword followed by the 
value to be returned. Return values can be of any data type. 

• JavaScript functions cannot be overloaded. A JavaScript function accepts zero or more argu- 
ments, regardless of the number of parameter variables defined for the function. All arguments 
are automatically assigned to the a r g u m e n t s array, which is a property of a function obj ect . 
Parameter variable data types are not predefined. 

• Values are passed by reference and by value. An object passed to a function is actually a 
reference to that object, offering full read/write access to properties and methods of that object. 
But other types of values (including object properties) are passed by value, with no reference 



56 



Chapter 4: JavaScript Essentials 



chain to the original object. Thus, the following nonsense fragment empties the text box when 
the onchange event fires: 

function emptyMe ( a rgl ) 
{ 

argl. value = ""; 

} 

<input type="text" val ue="Howdy" onchange="emptyMe ( thi s ) " > 
But in the following version, nothing happens to the text box: 

function emptyMe ( a rgl ) 
{ 

argl = " " ; 

} 

<input type="text" val ue="Howdy" onchange="emptyMe( thi s . val ue ) " > 
The local variable (argl) simply changes from "Howdy " to an empty string. 

Note 

The property assignment event handling technique in the previous example is a deliberate simplification to 
make the example very brief. It is generally better to use the more modern approach of binding events using the 
addEventLi stener( ) (NN6+/Moz/W3C) or attachEvent( ) (IE5+) methods. A modern cross-browser 
event handling technique is explained in detail in Chapter 32, "Event Objects." ■ 

• Error trapping techniques depend on JavaScript version. There was no error trapping in 
NN2 or IE3. Error trapping in NN3, NN4, and IE4 was event-driven in the web browser object 
model. JavaScript, as implemented in IE5+ and Mozilla, Safari, and other recent browsers, sup- 
ports try - catch and throw statements, as well as built-in error objects that are not depen- 
dent on the host environment. 

• Memory management is not under script control. The host environment manages memory 
allocation, including garbage collection. Different browsers may handle memory in different 
ways. 

• Whitespace (other than a line terminator) is insignificant. Space and tab characters may 
separate lexical units (for example, keywords, identifiers, and so on). 

• A line terminator is usually treated as a statement delimiter. Except in very rare construc- 
tions, JavaScript parsers automatically insert the semicolon statement delimiter whenever they 
encounter one or more line terminators (for example, carriage returns or line feeds). A semi- 
colon delimiter is required between two statements on the same physical line of source code. 
Moreover, string literals may not have carriage returns in their source code (but an escaped 
newline character ( \ n) may be part of the string). 



The Evaluator Sr. 

The Evaluator Sr. is a tool you can use in succeeding chapters to help you learn both core JavaScript 
and DOM terminology. The Evaluator provides an interactive workbench to experiment with expres- 
sion evaluation and object inspection. (In Chapter 8, "Programming Fundamentals, Part I," we will 
introduce a slimmed-down version we call The Evaluator Jr.) 



57 



Part I: Getting Started with JavaScript 



Figure 4-1 shows the top part of the page. Two important features differentiate this full version from 
the Jr. version in Chapter 8. 



FIGURE 4-1 



The Evaluator Sr. 



5 Th ■ rvaluilai M»VlB~i 'tilth.* 



Fitn Edil Udw lliflniy Bonkmnrfct Tanh Hilp 



Innimrri □□lEli?mi?nl9y1d-"ir!; f P _ i TmrHTML 



Sfr?o is Cine i if? lac <™ ad^^nyEB^niK^eTV- orod h"=e 
ij □cue lo the ail of tbalc acuncEFi. 



H*w tf rJip ninr/da >■■''{ Snud tnrn (« c«lrtr t* dbe rtinlflf rtufif (sunny 

Tlci! u a tit* tipv &a 

(.HianlitT S>mi ii]iiLiin t\i 




Tim cs a 

■ 1 1 r- . I 
--.:.•■!.: 

lent n Jl 



□ SuiilIe Chcckbo-i 

I ChociE dir Desired j'HtVrrriarice 



J_=. 



First, you can try some Mozilla secure features if you have Code Base Principles turned on for your 
browser (see Chapter 49, "Security and Netscape Signed Scripts," on the CD-ROM) and you check 
the Use Code Base Security check box (Netscape Navigator 4 or later/Moz only). Second, the page has 
several HTML elements preinstalled, which you can use to explore DOM properties and methods. As 
with the smaller version, a set of 26 one-letter global variables (a through z) are initialized and ready 
for you to assign values for extended evaluation sequences. 

Copy the evaluator.html and evaluator.js files from the companion CD-ROM to a local hard 
disk and set a bookmark for it in all your test browsers. Feel free to add your own elements to the 
bottom of the page to explore other objects. We describe a version of The Evaluator for embedding in 
your projects as a debugging tool in Chapter 48, "Debugging Scripts" (on the CD-ROM), where you 
can learn more built-in functionality of The Evaluator. 



58 



Part 1 1 



JavaScript Tutorial 



IN THIS PART 


Chapter 5 


Chapter 10 


Your First JavaScript Script 


Window and Document Objects 


Chapter 6 


Chapter 11 


Browser and Document Objects 


Forms and Form Elements 


Chapter 7 


Chapter 12 


Scripts and HTML Documents 


Strings, Math, and Dates 


Chapter 8 


Chapter 13 


Programming Fundamentals, Part 1 


Scripting Frames and Multiple 




Windows 


Chapter 9 




Programming Fundamentals, Part II 


Chapter 14 




Images and Dynamic HTML 



CHAPTER 



Your First JavaScript 
Script 



3 



i 



n this chapter, you write a simple script, the results of which you can see in 
your JavaScript-compatible browser. 



Two common ways of teaching spoken human languages are a) grammar lessons 
leading to eventual conversation and b) immersion in conversation leading to 
eventual grammar lessons. 

We like b). It's more fun (play enhances learning), you get to see results right 
away, and it more closely resembles the way we each learned our own native 
tongue. The grammar's always there to refer to, but let's kick things off to a good 
start by plunging in and making a little magic happen on the screen. 

Don't worry about memorizing every command and detail of syntax discussed 
in this chapter. Instead, relax and watch how the HTML markup and JavaScript 
statements become what you see in the browser. The details will soak in more 
quickly if you're enjoying yourself. 

We'll explain each line of code as we go along, although all the methods we use 
in this first tutorial will be explained in much greater detail later in the book. 
For now, just enter the scripts as presented and see that they do what they're 
supposed to do. 



IN THIS CHAPTER 



Creating a simple application 
consisting of an HTML page, 
a JavaScript script, and a CSS 
style sheet 



What Your First Script Will Do 

Our first tutorial script will insert the current date and time into a web page. 
(This is a further evolution of the "Hello, World" script we showed you in 
Chapter 3, "Selecting and Using Your Tools.") First, we'll create an HTML page 
that simply displays static content; then we'll add JavaScript to make it dynamic; 
and then we'll add styling to jazz it up. 

It's worth noting that this sequence — building HTML structure and then 
adding dynamic JavaScript and CSS for presentation — is not useful merely 
when learning; it's also a very decent model for everyday, real-world web 
site production. It's part of a larger sequence of development that might 



61 



Part II: JavaScript Tutorial 



include information design, graphic design, wireframe and proof-of-concept, HTML markup, 
server-side scripting, CSS styling, and JavaScript. Although it might be tempting to jump to the 
scripting first, that's sort of like spreading the icing before the cake is baked. JavaScript, like CSS, 
needs to know its context — the structure of the page in which it's operating. Also, working in this 
sequence encourages us to adhere to the principle of progressive enhancement, whereby everyone can 
get something out of the fundamental page, but those with user agents (such as browsers) with more 
capabilities can get even more out of it. By starting with the HTML page, we ensure that it's complete 
and makes sense even without JavaScript. 

These days most serious web production includes a server-side scripting language and database, such 
as PHP and MySQL, to provide the fundamental dynamic content as HTML markup. As server-side 
scripting is outside the realm of this book, we'll mention it from time to time, but we will otherwise 
assume a truly static HTML page. 



Entering Your First Script 

Launch your text editor and browser. You may also want to launch your standard file manager utility 
to monitor the files that you'll be creating in a folder on your computer. 

We'll be working offline throughout this book. All operations will happen locally on your computer 
and without Internet connectivity. If your browser offers to dial your Internet service provider (ISP) or 
begins dialing automatically, you can cancel or quit the dialing operation. If the browser's Stop button 
is active, you can click it to halt any network searching it may try to do. You may receive a dialog-box 
message or page indicating that the URL for your browser's home page (usually the home page of the 
browser's publisher — unless you've changed the settings) is unavailable. That's fine. You want the 
browser open, but you don't need to be connected to your ISP. If you're automatically connected to 
the Internet through a local area network in your office or school, or through cable modem or DSL, 
that's also fine. However, you don't need the network connection for now. 



Step 1 : The HTML document 

Figure 5-1 shows our first goal: a simple page with a headline and a paragraph of text. This is what 
our initial page will look like, allowing for differences in the way various browsers present content by 
default (in other words, that hasn't yet been styled by us). 

Enter the following HTML markup into a new text file and save it (with UTF-8 character encoding) 
with the name date-time . html : 



LISTING 5-1 



HTML Markup for "Date & Time": date-time.html 

<!D0CTYPE html> 
<html > 
<head> 

<rtieta http-equi v = "content-type" content="text/html ;charset=utf-8"> 
<title>Date & Time</title> 
</head> 



62 



Chapter 5: Your First JavaScript Script 



<body> 

<hl>Date & Time</hl> 
< p > 1 1 is currently <span i d = 
</body> 
</html > 



'output ">now</span>.</p> 



FIGURE 5-1 



Step 1 : Static HTML page. 



' i.it* ^ limp - hl-, f lll., HrH-iv 



m f/ti jWi Hyatt 
uuiua inn 



MiK-i lime 



Note 

Throughout this book, we will consistently use UTF-8 character encoding for our HTML files. A character 
encoding tells the browser how to display text characters, and the Unicode standard of UTF-8 is a splendid 
system that enables us to include virtually any world language in our HTML files. It will serve you well in your 
web site production. 

From the start, get into the habit of saving your files with UTF-8 encoding. Many text editors enable you to 
choose the encoding in the Save As... dialog, as well as set the default encoding for future files so that you 
don't have to specify it each time. If your text editor doesn't give you this option, keep using it for now, but 
start looking around for another editor that will. ■ 



Now open the document in your browser. You can do this by double-clicking on the file in the file 
manager screen or by choosing Open or Open File in the File menu of your browser. 



63 



Part II: JavaScript Tutorial 



If you typed all lines as shown, the document in the browser window should look like the one in 
Figure 5-1 (with minor differences for your computer's operating system and browser version). 

Let's examine the details of the document so that you understand some of the finer points of what the 
markup is doing. 

DOCTYPE 

<!D0CTYPE html> 

The DOCTYPE tells the browser how to render the document. Which DOCTYPE you use greatly affects 
CSS styling and markup validation. The DOCTYPE we're using in this book is the one for HTML5, but 
you can replace it with either the DOCTYPE for HTML 4.01-Strict for validation purposes: 

<!D0CTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/html4/strict.dtd"> 

or with the one for XHTML 1.0-Strict (along with a few other changes in markup style): 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml 1 /DTD/xhtml 1-stri ct.dtd"> 

Note 

XHTML style, if you intend to follow its conventions, requires all lowercase tags and attribute names. While 
the listings in this book are HTML, which accepts either upper- or lowercase tags and attributes, we will use 
lowercase consistently in order to remain compatible with both standards. 

XHTML also requires several modifications to the HTML we're using in these examples. For more details on this, 
see the Introduction. ■ 

html 

The markup continues: 
<html > 
</html > 

The entire page will always reside inside the html element, which declares the type of markup. The 
html element has just two children, head and body. 

head 

<head> 
</head> 

The head element may contain a variety of child elements that convey information about a 
document but that are not normally rendered as document content. The head must have, at 
minimum, two children, a meta element defining the character set, and a ti tl e: 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Date & Time</title> 



64 



Chapter 5: Your First JavaScript Script 



meta tags are a lengthy topic unto themselves. For now, just enter this one exactly as above. HTML5 
can accept a shorter version: 

<meta charset="UTF-8"> 

However, the longer version works for all three markup types (HTML 4.01, HTML5, and XHTML 
1.0). Note that the meta tag is "empty" and does not take a closing </meta> tag. All the information 
it conveys is in its attributes, here http-equiv and content. 

ti tl e, on the other hand, does require a closing tag; together they surround their content. The title 
"Date & Time" is entered as Date &amp ; Time, using the HTML entity &amp ; for the ampersand. 
There are four characters that must always be converted to HTML entities if they appear in the content 
of the page — attribute values and the text enclosed by tags — in order not to confuse the parsing 
engine: 

< < 

> > 

& & 

" " 

This last one is the straight double quote used in HTML markup, not the curly quotes common in 
typeset text. 

body 

<body> 
</body> 

The body element contains the document's content — its structure, text, images, multimedia objects, 
and so on. 

headline 

<hl>Date & Time</hl> 

We use the headline tags hi through h6 to create an outline structure in a document. Ordinarily, a 
document page will have only one hi to reiterate the page title, with all other headlines, starting with 
h 2 , nested beneath. 

In the bad old days, people chose headline tags purely for their default appearance. Today, we use 
them just as you would use the numbers in a nested outline structure, and we control the appearance 
of all text from the style sheet. 

paragraph 

<p> I t is currently <span i d="output " >now</span> . </p> 

Finally, this is the paragraph of text where JavaScript will insert the current date and time. The span 
element has an ID (output) that JavaScript will use to locate it so that our script can replace the 
contents of the span with the actual date and time. 

So, that's the static HTML page. Even after we plug in the JavaScript, anyone looking at the page with 
a user agent that doesn't support JavaScript (such as a search engine), or that has it turned off, will 



65 



Part II: JavaScript Tutorial 



see just what we're seeing here. The page isn't terrifically informative in its current state, but at least 
it isn't broken. For public web sites, scripting should add value to the page rather than be mission 
critical. 

Step 2: Adding JavaScript 

Next, let's create the JavaScript for our page. Now is a good time to instill some good JavaScript habits 
that will be important to you throughout all your scripting ventures. First, JavaScript is case-sensitive. 
Therefore, you must type every word in your script with the correct uppercase and lowercase letters. 
When a line of JavaScript doesn't work, look for the wrong case first. Always compare your typed 
code against the listings printed in this book and against the various vocabulary entries discussed 
throughout it. 

Second, notice that each JavaScript statement ends in a semicolon. These trailing semicolons — which 
you can think of as periods at the end of sentences — technically are optional in JavaScript, but we 
strongly recommend that you use them to remove ambiguity from your scripts. If you someday inves- 
tigate other programming languages such as PHP, Java, or C++, you'll find that those semicolons are 
required. All the JavaScript listings in this book use semicolons. 

Create a second text file in your editor named date-time.js and enter the following script: 

Note 

A JavaScript comment is any text contained between a double forward slash (//) and the end of the current 
line, or between slash-asterisk (/*) and asterisk-slash (*/). Comments are ignored by the JavaScript interpreter 
and are added purely to help human readers understand what's going on in the code. Therefore, you don't have 
to enter the comments exactly as you see here, but we do recommend that you get in the habit of commenting 
your code. Other programmers and your own future self will appreciate it! ■ 



LISTING 5-2 



JavaScript Code for "Date & Time": date-time.js 

// tell the browser to run this script when the page has finished loading 
wi ndow . onl oad = i nsertDateTime ; 

// insert the date & time 
function i nsertDatef i me ( ) 

{ 

// ensure a DOM-aware user agent 

if (! document . getEl ementBy Id ) return; 

if (! document . createTextNode ) return; 

// create a date-time object 
va r oNow = new Date ( ) ; 

// get the current date & time as a string 
var sDatefime = oNow . toLoca 1 eSt ri ng ( ) ; 

// point to the target element where we want to insert the date & time 
var ofarget = document . getEl ementByldC ' output ') ; 



66 



Chapter 5: Your First JavaScript Script 



// make sure the target is foimd 
if ( ! oTarget ) return ; 

// delete everything inside the target 

while ( oTa rget . f i rstChi 1 d ) 

{ 

oTarget.removeChild(oTarget.firstChild); 

} 

// use the date-time string to create a new text node for the page 
var oNewfext = document . createTextNode ( sDatefi me ) ; 

// insert the new text into the span 
oTarget.appendChild( oNewfext ) ; 

) 



To connect this JavaScript file to the HTML file, we need to add a scri pt element to the HTML 
head. Bring date-time.html back into your text editor and add the line highlighted below: 

<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Date & Time</title> 

<script type=" text/ javascript" src=" date -time. js"X/script> 

</head> 



The scri pt tag identifies the MIME type of the linked JavaScript file and gives its name (and path, 
in case it's not located in the same folder as the HTML file itself)- This causes the browser to read the 
JavaScript file as it's building the document page. The JavaScript interpreter within the browser vali- 
dates and compiles the script, and runs it immediately, even before the rest of the HTML document 
has been read. 

Now let's walk through the JavaScript code line by line so that you can see what it's doing. 
Triggering the event 

Here's a problem: Our script is going to insert the date and time into a paragraph in the page, but 
the browser reads and runs our JavaScript code before it's had a chance to read the HTML body. The 
paragraph into which we want to insert the new content won't even exist yet in the browser's memory 
when the JavaScript starts running. 

Our solution is simply to tell JavaScript not to perform the insertion until the document has been 
fully read into memory. We do this using the onl oad event. Elements of the page — called objects 
in the Document Object Model (DOM) — can be made sensitive to a number of events, such as the 
click of a mouse or the press of a key. The onload event of the wi ndow object is triggered when the 
document finishes loading into the browser. 

// tell the browser to run this script when the page has finished loading 
window. onl oad = insertDatefime; 



67 



Part II: JavaScript Tutorial 



// insert the date & time 
function i nsertDateTime( ) 
{ 

} 

In this case, we're telling JavaScript to call the insertDateTime( ) function when the document has 
finished loading. The date and time insertion routine that depends on the document having loaded is 
thus deferred until the browser has the target paragraph in memory. 

Ensuring a safe environment 

Once the document finishes loading into the browser, the wi ndow . on 1 oad event has been triggered, 
and the insertDateTime( ) function is called, the first thing the script does is to make sure it's 
being interpreted by a modem browser that speaks the same language: 

// ensure a DOM-aware user agent 

if (! document . getEl ementBy Id ) return; 

if (! document . createTextNode ) return; 

getEl ementBy Id( ) and createTextNode ( ) are two DOM methods we're using in this function 
that some old JavaScript interpreters won't understand. The exclamation mark (!) means "not," and 
return tells JavaScript to stop running the current function; so, the first statement means, "If you 
aren't aware of the get El ementBy I d ( ) method for the document object, exit this function." If we 
didn't include these safeguards, a legacy browser or its JavaScript interpreter would likely crash when 
trying to run the code that follows. 

A crash can be as minor as the JavaScript interpreter stopping cold (leaving us with a plain HTML 
page and no JavaScript functionality at all) or as major as the whole browser freezing up and needing 
to be rebooted. Neither event is welcome. For many pages, we'll be writing JavaScript to perform sev- 
eral tasks, some of which can be executed by legacy browsers and others that can't. We want to guide 
the browser around the parts it can't handle, so it will run the parts it can. Preventing old JavaScript 
versions from crashing on the reefs of modern methods is a hallmark of professional piloting. 

We subscribe to the principles of graceful degradation and progressive enhancement, whereby browsers 
that can't take advantage of particular features are let down gently and allowed to do the best they 
can. A fundamental courtesy of scripts that interact with the DOM is to turn away legacy JavaScript 
interpreters that aren't DOM-aware. 

The old-school way of checking for old JavaScript interpreters is browser-sniffing, which examines the 
browser type as reported by the navi gator object. Unfortunately, these claims of identity can't be 
relied on. What can be trusted is the JavaScript interpreter's own knowledge of which methods it's 
capable of executing, and that's the principal safety feature we use today. 

Generating the date and time 

The text we're going to insert into this document is the current date and time (according to the clock 
in the user's computer). JavaScript makes this easy: we create a Date object and use one of its many 
methods to produce the string: 

// create a date-time object 
va r oNow = new Date ( ) ; 



68 



Chapter 5: Your First JavaScript Script 



// get the current date & time as a string 
var sDateTime = oNow. toLocal eStri ng( ) ; 

This code sets the variable oNow to a new Date object. Once we have that, we use its 
toLocal eStri ng( ) method to output a text string containing something like: 

Thursday, August 20, 2009 4:16:05 PM 

We capture the date and time string in variable sDateTime, which we'll use in a moment to output 
to the page. 

The beauty of the toLocal eStri ng( ) method is that it outputs the date and time formatted 
according to the user's settings and in the user's time zone. If two people run this exact same code 
at the same moment on opposite sides of the earth, they're likely to get two different dates and times 
expressed in two different formats and in two different languages. You'll learn a lot more about the 
Date object in the chapters ahead, particularly Chapter 12, "Strings, Math, and Dates," and Chapter 
17, "The Date Object." 

Note 

In this example script, oNow is a Date object and sDateTime is a text string. One of the zillion flavors of 
programming style is the so-called Systems Hungarian notation in which each variable name begins with an 
indication of its type — here o for object, s for string, i for integer, and so on. Naming variables like this is 
purely optional, and for the programmer's own benefit. JavaScript doesn't care what the names are, as long 
as no keywords or illegal characters are used. JavaScript is a "dynamically typed" language in which the same 
variable can be set arbitrarily with numeric, string, Boolean, and object reference values. Some programmers 
like to maintain only one type of value in each variable to help keep the code easy to manage and debug. Using 
Hungarian notation can make these artificial variable types easier to remember. ■ 

Finding the target 

The next step is to insert the date and time into the document exactly where we want it. To do that, 
we need to: 

1 . Refer to the target span element. 

2. Delete any text already inside the element. 

3. Insert new text inside the element. 

To refer to the o u t p u t s p a n , the script uses the industry-standard way to refer to any HTML ele- 
ment that has an ID attribute: 

// point to the target element where we want to insert the date & time 
var olarget = document. getEl ementById( 'output' ) ; 

The first statement locates the target element in the HTML page by its ID (output) and stores a ref- 
erence to that object in variable oTarget. The HTML specification mandates that every element ID 
must be unique on the current page. Even if we accidentally use the same ID more than once on the 
page, the getEl ementById( ) method returns only the first instance. So, we know that this method 
will locate just one element (if it's there at all) — in this case, the span we marked up in the HTML: 

<p> I t is currently <span i d="output " >now</span> . </p> 



69 



Part II: JavaScript Tutorial 



Notice that when we call getEl ementById( ), we specify the element's ID (output) but not its tag 
name (span). In the HTML markup we could move the attribute id=" output" from the span to 
any other element within the page, and our script would attempt to operate on that element instead. 
If you think about it, that's pretty cool. It means that, even though the markup and the script have to 
agree about the target element's ID, the script can potentially operate regardless of which tags are used 
in the markup. It's that kind of flexibility that can make for some truly versatile JavaScript functions 
down the road. 

If we omit or misspell the ID in the markup, getElementByldO will return a null value. To cover 
our bases, we test for that: 

// make sure the target is found 
if ( ! of a rget ) return ; 

Similarly to the previous if- tests, this one says, "If the variable of a rget doesn't exist or has 
a null value, return from this function." Adding such reality checks to a script will help make 
it bulletproof. Developing habits like this will really benefit you when you're juggling dozens 
of elements on a page or working on pages that have been generated by numerous people 
and processes. 

This is an opportunity to warn the user in case something is seriously wrong — for example: 

if (lofarget) return a 1 ert ( "Wa rn i ng : output element not found"); 

However, since in most cases there's really nothing that a typical web site visitor can do about a prob- 
lem like this, it might be best for the script to stop quietly or find something else to do, such as notify 
the web master. 

Deleting what's there 

Our HTML document comes pre-populated with some text we want to replace: 

<p> 1 1 is currently <span i d="output">now</span> . </p> 

We want to delete the text within the span and then insert new content. In the DOM that represents 
the contents of the page, the span is the parent of everything within it. Right now there's just a sin- 
gle child — the word "now" — but we'd like this script to run successfully even if the HTML is later 
modified to include other markup within the target element. 

Figure 5-2 shows that paragraph from a DOM perspective. The p element has three children: two text 
nodes and the span. The span has just one child: a text node containing the value "now". 



FIGURE 5-2 



A DOM's-eye view of the date and time paragraph before insertion. 





P 




















"It is currently " 




span 







'now" 



70 



Chapter 5: Your First JavaScript Script 



To remove the contents of the span, execute a little loop that deletes child elements one at a time, as 
long as there are any to delete: 

// delete everything inside the target 

while ( oTa rget . f i rstChi 1 d ) 

{ 

oTarget.removeChild(oTarget.firstChild); 

} 

Given our current markup, this loop will execute just once. A while loop will repeat as 
long as the expression inside the parentheses tests true. When it begins, the property 
oTarget . f i rstChi 1 d is evaluated: Does the object oTarget have a first child node? The 
answer is yes (true) because the text node "now" is there. Inside the loop, the removeChi 1 d ( ) 
method deletes that first child. Then JavaScript loops and asks the same question again: Does 
oTarget . f i rstChi 1 d exist? The answer is no (fal se), so JavaScript stops processing the whi 1 e 
loop and resumes execution after the closing brace. 

Inserting the date and time 

Finally, we create a new node in the DOM that contains the text we want, and insert that into the 
span: 

// use the date-time string to create a new text node for the page 
var oNewText = document . createTextNode ( sDateTi me ) ; 

// insert the new text into the span 
oTarget. appendChild(oNewText) ; 

sDateTime is the string we generated from the Date object a few statements before. We call a 
method attached to the document object that creates a new text node with the date and time string 
as its value. At this point, the text node isn't yet part of the visible document content; it's waiting in 
the wings. We bring it on stage using the target element's appendChild() method. 

The paragraph structure now looks like that shown in Figure 5-3. It's the same structural shape, but 
the span now has a new child. 



FIGURE 5-3 



The date and time paragraph after insertion. 





P 




















"It is currently " 




span 





"Thursday, August 20, 2009 4:16:05 PM" 



71 



Part II: JavaScript Tutorial 



Debugging 

When you've saved the JavaScript file and the HTML file with its script tag, you should be able to load 
the HTML page into your browser and see the word "now" replaced by the current date and time. 

If you can't, take the time now to track down the problem and fix it. In the process, you'll learn 
important details about JavaScript that will help your future coding go faster and more smoothly. 

Proofread the HTML markup and JavaScript code to make sure that they match the preceding list- 
ings. The two critical points in the markup will be the scri pt tag and its attributes that point to 
the JavaScript file, and the span tag and its ID that JavaScript will look for. In the JavaScript file, 
make sure that every statement is spelled accurately, including spaces, punctuation, and upper- and 
lowercase letters. 

If you are unsure about the HTML, it's always a good idea to validate it in the W3C HTML 
Validator, available at http://validator.w3.org/. Select either Validate by File 
Upload to upload the HTML file from your computer or Validate by Direct Input to copy 
and paste the HTML markup from your text editor into the Validator. At this writing, 
all the examples in this book with an HTML5 DOCTYPE will register one warning: Using 
experimental feature: HTML5 Conformance Checker. This is an informational message, 
not an error. Your goal is to get a green banner at the top of the Validator results page that says, 
This document was successfully checked as HTML5! 

Check your browser's error console to see if it's reporting an error. If so, it will likely tell you the 
position of the error in the script file. 

For further steps, see Chapter 48, "Debugging Scripts." 



Step 3: Adding style 

Finally, to illustrate how a third component of a typical web page ties in, let's add a simple style sheet 
to the mix. Style sheets tell the browser how the page should appear — everything from the layout to 
font choices to background colors. 

Create a new text file in your editor, enter the following style sheet script, and save it as 
date-time . ess: 



LISTING 5-3 



CSS Code for "Date & Time": date-time.css 

©charset "utf -8" ; 



{ 

margin: 0; 

font-family: sans-serif; 

} 

hi 

{ 

font-size: 10 em; 
color: #DDF; 



72 



Chapter 5: Your First JavaScript Script 



} 
p 

{ 

position: absolute; 
top : 2 . 5em ; 
1 eft : 1 . 5em ; 
font-size: 2 em; 
font-weight: bold; 
color: #338; 

1 

//output 

{ 

font-sty le: italic; 
color: #C33; 

) 



To link this style sheet to the HTML file, add a 1 i nk element to the HTML head. Bring 
date-time, html back into your text editor and add this line: 

<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Date & Time</title> 

< 1 ink href="date-time.css" rel = "stylesheet" type="text/css" media="al 1 "> 

< s c r i p t type="text/ javascri pt" src=" date-time. js"X/script> 
</head> 



Save the style sheet, save the modified HTML file, and reload the page in your browser. It should look 
pretty much like Figure 5-4. 

Briefly, the style sheet is a list of rendering rules to be applied to the elements of the page. The basic 
syntax is as follows: 

selector ( property: value; [...] } 
Our style sheet begins with a character-encoding directive: 

@charset "utf-8" ; 
Note that this matches the character encoding for the HTML file. 

The * (wildcard) selector applies to all elements on the page. Here, it zeroes out default margins and 
sets the font-family for all text. 

The hi selector sets the headline font size to ten times the base font size (lem = 100% of base) and 
sets the font color to a pale blue with the RGB (red-green-blue) hexadecimal code of DDF. 

The p selector applies to all paragraphs on the page (there is only one). The position, top, 
and 1 eft properties allow us to position the paragraph on top of the headline. We set the font 
weight to bold to make sure it's readable against the pale headline, and the text color to a dark blue 
with RGB #338. 



73 



Part II: JavaScript Tutorial 



FIGURE 5-4 



Step 3: The styled page. 



5 Date Si Time - Mozllla Firefox 


^^■BH -JhIjsJ 


Fife- fijlt view Htitorv Ssokmarto I00I5 Hflp 




Date & Time 







It is currently Thursday, August 20, 2009 4:16:05 PM, 



Don? 



The #output selector applies to the element with an ID of output. Here, we change the font-style 
to italic and the text color to a dark red with RGB #C33. This element also inherits properties from its 
parent, including the bold font-weight. 

To learn more about Cascading Style Sheets (CSS) go to www.w3.org/Style/CSS/. 



Have Some Fun 

Once you get this script working properly, play around with it a bit. Move the output ID from one 
element to another. Change the text that gets inserted. Get comfortable tweaking the markup, the 
script, and the style sheet to get effects that you want. After each change, save the file and reload the 
page in your browser to check your progress. Don't be afraid to make mistakes while you're learning. 
You can always undo a change that goes awry. Remember that play is the best way to learn! 



74 



Chapter 5: Your First JavaScript Script 



Exercises 



1 . Perform a single cut-and-paste operation on the HTML markup in Listing 5-1 to cause 
JavaScript to replace the entire paragraph with the date and time, not just the span. 
Hint: After your edit, the paragraph will still contain text and a span element. 

2. With the change of markup you've just made, consider the while loop in JavaScript 
Listing 5-2. Write out each step that the loop will take in deleting the contents of 
the paragraph. 

3. Again given the HTML edit you made in Exercise 1, decide which change(s) to the style sheet 
in Listing 5-3 would be necessary in order to assign the paragraph the same font and color 
attributes that the span had before. 



75 



Browser and 
Document Objects 



CHAPTER 

ft 



In this chapter, you'll see several practical applications of JavaScript and 
begin to see how a JavaScript-enabled browser turns familiar HTML 
elements into objects that your scripts control. This tutorial teaches concepts 
and terminology that apply to modern browsers, with special focus on standards 
compatibility to equip you to work with today's and tomorrow's browsers. You 
should study this tutorial in conjunction with any of the following browsers: 
Internet Explorer 5 or later (Windows or Macintosh), any Mozilla-based browser 
(Firefox, Netscape 7 or later, or Cammo), Apple Safari, or Opera 7 or later. 



Scripts Run the Show 



If you have authored web pages with HTML, you are familiar with how HTML 
tags influence the way content is rendered on a page when viewed in the 
browser. As the page loads, the browser recognizes angle-bracketed tags as 
formatting instructions. Instructions are read from the top of the document 
downward, and elements defined in the HTML document appear on-screen 
in the same order in which they appear in the document's source code. As an 
author, you do a little work one time and up front — adding the tags to text 
content — and the browser does a lot more work every time a visitor loads the 
page into a browser. 

Assume for a moment that one of the elements on the page is a text input field 
inside a form. The user is supposed to enter some text in the text field and then 
click the Submit button to send that information back to the web server. If that 
information must be an Internet email address, how do you ensure the user 
includes the @ symbol in the address? 

One way is to have a program running on the web server — such as one written 
in PHP, ASP, ColdFusion, or a Common Gateway Interface (CGI) language, 
such as Perl — inspect the submitted form data after the user clicks the Submit 
button and the form information is transferred to the server. If the user omits 
or forgets the @ symbol, the server-side program sends the page back to the 
browser — but this time with an instruction to include the symbol in the 



IN THIS CHAPTER 



What client-side scripts do 

What happens when a 
document loads 

How the browser creates 
objects 

How scripts refer to objects 

What distinguishes one object 
from another 



77 



Part II: JavaScript Tutorial 



address. Nothing is wrong with this exchange, but it can mean a slight delay for the user in finding 
out that the address does not contain the crucial symbol. Moreover, the web server has to expend 
some of its resources to perform the validation and communicate back to the visitor. If the web site is 
a busy one, the server may try to perform hundreds of these validations at any given moment, proba- 
bly slowing the response time to the user even more. 

Now imagine that the document containing that text input field has some intelligence built into it 
that makes sure the text-field entry contains the @ symbol before ever submitting one bit (literally!) 
of data to the server. That kind of intelligence would have to be embedded in the document in some 
fashion — downloaded with the page's content so it can stand ready to jump into action when called 
upon. The browser must know how to run that embedded program. Some user action must start the 
program, perhaps when the user clicks the Submit button. If the program runs inside the browser and 
detects the lack of the @ symbol, an alert message should appear, to bring the problem to the user's 
attention. The same program should also be capable of deciding whether the actual submission can 
proceed or whether it should wait until a valid email address is entered in the field. 

This kind of pre-submission data entry validation is but one of the practical ways JavaScript adds 
intelligence to an HTML document. Considering this example, you might recognize that a script must 
know how to look into what is typed in a text field; a script must also know how to let a submission 
continue and how to abort the submission. A browser capable of running JavaScript programs con- 
veniently treats elements such as the text field as objects. A JavaScript script controls the action and 
behavior of objects, most of which you see onscreen in the browser window. 



When to Use JavaScript 

With so many web-oriented development tools and languages at your disposal, you should focus your 
client-side JavaScript efforts on tasks for which they are best suited. When faced with a web applica- 
tion task, we look to client-side JavaScript for help with the following requirements: 

• Data entry validation. If form fields need to be filled out for processing on the server, we let 
client-side scripts prequalify the data entered by the user. 

• Serverless CGIs. We use this term to describe processes that, were it not for JavaScript, would 
be programmed as CGIs on the server, yielding slower performance because of the interactivity 
required between the program and the user. This includes tasks such as small data collection 
lookup, modification of images, and generation of HTML in other frames and windows based 
on user input. 

• Dynamic HTML interactivity. It's one thing to use DHTML's capabilities to position elements 
precisely on the page; you don't need scripting for that. But if you intend to make the content 
dance on the page, scripting makes that happen. 

• CGI prototyping. Sometimes you want a server-side program to be at the root of your appli- 
cation because it reduces the potential incompatibilities among browser brands and versions. 
It may be easier to create a prototype of the CGI in client-side JavaScript. Use this opportunity 
to polish the user interface before implementing the application in your server-side script of 
choice. 

• Offloading a busy server. If you have a highly- trafficked web site, it may be beneficial to con- 
vert frequently-used CGI processes to client-side JavaScript scripts. After a page is downloaded, 
the server is free to serve other visitors. Not only does this lighten server load, but users also 
experience quicker response from the application embedded in the page. 



78 



Chapter 6: Browser and Document Objects 



• Adding life to otherwise-dead pages. HTML by itself is pretty flat. Adding a blinking chunk 
of text doesn't help much; animated GIF images more often distract from, rather than contribute 
to, the user experience at your site. But if you can dream up ways to add some interactive zip to 
your page, it may engage the user and encourage a recommendation to friends or repeat visits. 

• Creating web pages that "think." If you let your imagination soar, you may develop new, 
intriguing ways to make your pages appear "smart." For example, in the application Intelli- 
gent "Updated" Flags (Chapter 57 on the CD-ROM), you see how (without a server CGI or 
database) an HTML page can "remember" when a visitor last came to the page. Then, any items 
that have been updated since the last visit — regardless of the number of updates you've done 
to the page — are flagged for that visitor. That's the kind of subtle, thinking web page that best 
displays JavaScript's powers. 



Note 

Web pages and applications intended for public access should not rely exclusively on JavaScript to supply 
critical functions. Make sure that your primary data and web site functionality are accessible to visitors who 
have JavaScript turned off and to user agents that don't interpret JavaScript, such as search engines and mobile 
devices. Let your scripting enhance the experience for the majority of visitors who have JavaScript-enabled 
browsers, but don't let your web site be broken for the rest. ■ 



The Document Object Model 

Before you can truly start scripting, you should have a good feel for the kinds of objects you will be 
scripting. A scriptable browser does a lot of the work of creating software objects that generally rep- 
resent the visible objects you see in an HTML page in the browser window. Obvious objects include 
form controls (text boxes and buttons) and images. However, there may be other objects that aren't so 
obvious by looking at a page, but that make perfect sense when you consider the HTML tags used to 
generate a page's content — paragraph objects or frames of a frameset, for example. 

To help scripts control these objects — and to help authors see some method to the madness of 
potentially dozens of objects on a page — the browser makers define a document object model (DOM). 
In this context, a model is the organization of objects on the page. 

Evolution of browser DOMs has caused much confusion and consternation among scripters due to a 
lack of compatibility across succeeding generations and brands of browsers. Fortunately, the DOM 
world is stabilizing around a formal specification published by the World Wide Web Consortium 
(W3C). Today's modern browsers continue to support some of the "old ways" of the earliest DOM 
because so much existing script code on the Web relies on these traditions continuing to work. (You'll 
see some of these in Chapter 11, "Forms and Form Elements.") But with the vast majority of browsers 
in use today supporting the basic W3C DOM syntax and terminology, scripters should aim toward 
standards compliance whenever possible. 



HTML structure and the DOM 

An important trend in HTML markup is applying markup solely to define the structure of a document 
and the context of each piece of content in the document. The days of using only HTML tags to influ- 
ence the appearance of a chunk of text are drawing to a close. It is no longer acceptable to enclose 
a line of text in, say, an < h 1 > tag because you want the line to appear in the text size and weight 
that browsers automatically apply to text tagged in that way. An < h 1 > element has a special context 



79 



Part II: JavaScript Tutorial 



within a document's structure: a first-level heading. In today's HTML world, if you wish to display a 
stand-alone line of text with a particular style, the text would likely be in a simple paragraph (<p>) 
tag; the precise look of that paragraph would be under the control of a Cascading Style Sheet (CSS) 
rule. Current practice even frowns upon the application of <b> and <i > tags to assign boldface and 
italic styles to a span of text. Instead, surround the text with a contextual tag (such as the <em> ele- 
ment to signify emphasis), and define the CSS style you wish applied to any emphasized text in the 
document. 

The result of applying strict structural design to your HTML tagging is a document that has 
a well-defined hierarchy of elements based on their nesting within one another. For example, 
a well-formed HTML 4.01 document has the following minimum elements: 

• Document type declaration 

• HTML 

• Head 

• Character encoding 

• Title 

• Body 

• Block-level content 

The HTML markup for this empty document might look like this: 

<!D0CTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 

"http://www.w3.org/TR/html4/strict.dtd"> 
<html > 

<head> 

<meta http-equi v="Content-Type" content="text/html ; 
charset=utf -8"> 

<titl eX/titl e> 
</head> 
<body> 

<p></p> 
</body> 
</html > 

Viewed as a family tree in which every child has just one parent, as shown in Figure 6-1, an HTML 
document must always have two children, DOCTYPE and html . 

The DOCTYPE tells the browser which version of markup is being used, critical information for 
markup validation and the interpretation of style sheet rules, html has two required children, head 
and body. The head must minimally contain a met a element that specifies the character encoding 
and a title, and may also contain a variety of other children such as script and style sheet links. 
Elements in the head ordinarily don't appear as objects on the document page, but tell the browser 
how to configure the document, and can radically affect its appearance and behavior. The body 
contains the text, images, and other elements that we ordinarily think of as being page content; it 
must minimally contain at least one block-level element such as a headline, paragraph, or division. 

Although we're using the much simpler DOCTYPE tag for HTML5 in this book, 
<!D0CTYPE html> 



80 



Chapter 6: Browser and Document Objects 



FIGURE 6-1 



Element hierarchy of an empty HTML 4.01 document. 



document 



DOCTYPE 



html 



head 



body 







I 


meta 




title 


character 
encoding 





we adhere to the markup requirements for HTML 4.01 so that our HTML markup will validate, to 
the greatest extent possible, as both HTML 4.01 and HTML5 in order to provide valid examples for 
whichever branch of markup you choose to pursue. 

The DOM in a browser window 

As its name implies, the formal DOM focuses primarily on the HTML document and the content 
nested inside it. From a practical standpoint, however, scripters often need to control the environment 
that contains the document: the window. The wi ndow object is the top of the hierarchy that browser 
scripts work with. The basic structure of the object model in modern browsers (given an empty HTML 
document) is shown in Figure 6-2. 



FIGURE 6-2 



Basic object model for all modern browsers. 



window 



navigator 



screen 



history 



location 



document 



81 



Part II: JavaScript Tutorial 



To give you a sense of the relationships among these top-level objects, the following describes their 
respective roles: 

• window object. At the very top of the hierarchy is the window. This object represents the 
content area of the browser window where HTML documents appear. In a multiple-frame envi- 
ronment, each frame is also a window (but don't concern yourself with this just yet). Because 
all document action takes place inside the window, the window is the outermost element of the 
object hierarchy. Its physical borders contain the document. 

• navigator object. This is the closest your scripts come to accessing the browser program, pri- 
marily to read the browser's claims of brand and version. This object is read-only, protecting the 
browser from inappropriate manipulation by rogue scripts; however, as you'll see, navigator 
can't be relied on to report the actual make, model, and version of the current browser. 

• screen object. This is another read-only object that lets scripts learn about the physical envi- 
ronment in which the browser is running. For example, this object reveals the numbers of pixels 
high and wide available in the monitor. 

• hi story object. Although the browser maintains internal details about its recent 
history (such as the list available under the Back button), scripts have no access to the details. 
At most, this object assists a script in simulating a click of the Back or Forward button. 

• location object. This object is the primary avenue to loading a different page into the cur- 
rent window or frame. URL information about the window is available under very controlled 
circumstances so that scripts cannot track access to other web sites. 

• document object. Each HTML document that gets loaded into a window becomes a 
document object. The document object contains the content that you are likely to script. 
Except for the html , head, and body element objects that are found in every HTML 
document, the precise makeup and structure of the element object hierarchy of the document 
depend on the content you put into the document. 



When a Document Loads 

Programming languages such as JavaScript are convenient intermediaries between your mental image 
of how a program works and the true inner workings of the computer. Inside the machine, every 
word of a program code listing influences the transformation and movement of bits (the legendary Is 
and Os of the computer's binary universe) from one RAM storage slot to another. Languages and object 
models are inside the computer (or, in the case of JavaScript and the DOM, inside the browser's area 
of the computer) to make it easier for programmers to visualize how a program works and what its 
results will be. The relationship reminds us of knowing how to drive an automobile from point A to 
point B without knowing exactly how an internal-combustion engine, steering linkages, and all that 
other internal "stuff works. By controlling high-level objects such as the ignition key, gearshift, gas 
pedal, brake, and steering wheel, we can get the results we need. 

Of course, programming is not exactly like driving a car with an automatic transmission. Even script- 
ing requires the equivalent of opening the hood and perhaps knowing how to check the transmission 
fluid or change the oil. Therefore, now it's time to open the hood and watch what happens to a docu- 
ment's object model as a page loads into the browser. 

A simple document 

Figure 6-3 shows the HTML and corresponding object model for a document that we'll be adding 
to in a moment. The figure shows only the document object portion; the wi ndow object and its 



82 



Chapter 6: Browser and Document Objects 



other top-level objects (including the document object) are always there, even for an empty docu- 
ment. When this page loads, the browser maintains in its memory a map of the objects generated by 
the HTML tags in the document. The body must contain block-level content, but we haven't added 
that yet. 



FIGURE 6-3 



Object map of an empty document. 



<!D0CTYPE 
<html> 
<head> 
<meta . 
<titl e) 
</head> 
<body> 

</body> 
</html > 



.> 

7title> 



document 



DOCTYPE 



html 



head 



body 



meta 



character 
encoding 



title 



Add a paragraph element 

Now, we modify the HTML file to include an empty paragraph element and reload the document. 
Figure 6-4 shows what happens to both the HTML and the object map, as constructed by the browser 
(changes shown in boldface). Even though no content appears in the paragraph, the <p> tags are 
enough to tell the browser to create that p element object. Also note that the p element object is con- 
tained by the body element object in the hierarchy of objects in the current map. In other words, the 
p element object is a child of the body element object. The object hierarchy matches the HTML tag 
containment hierarchy. 



Add paragraph text 

We modify and reload the HTML file again, this time inserting the text of the paragraph between the 
element's start and end tags, as shown in Figure 6-5. A run of text extending between tags is a spe- 
cial kind of object in the DOM called a text node. A text node always has an element acting as its 
container. Applying the official genealogy metaphor to this structure, this text node is a child of its 
parent p element. We now have a branch of the document object tree that runs several generations: 
document O html O body O p ■£> text node. 



Make a new element 

The last modification we make to the file is to wrap a portion of the paragraph text in an <em> tag 
to signify emphasis for the enclosed text. This insertion has a large effect on the hierarchy of the p 
element object, as shown in Figure 6-6. The p element goes from having a single (text node) child to 
having three children: two text nodes with an element between them. In the W3C DOM, a text node 



83 



Part II: JavaScript Tutorial 



cannot have any children and therefore cannot contain an element object. The bit of the text node 
now inside the em element is no longer a child of the p element, but a child of the em element. That 
text node is now a grandchild of the p element object. 

Now that you see how objects are created in memory in response to HTML tags, the next step is to 
figure out how scripts can communicate with these objects. After all, scripting is mostly about control- 
ling these objects. 



FIGURE 6-4 



Adding an empty paragraph element. 



<!D0CTYPE . . .> 
< html > 
<head> 
<meta . . . > 
<title></title> 
</head> 
<body> 

<p></p> 
</body> 
</html > 



document 



DOCTYPE 



html 



head 



body 



meta 



character 
encoding 



title 



FIGURE 6-5 



Adding a text node to the p element object. 



<!D0CTYPE . . .> 
<html > 
<head> 
<meta . . . > 
<title></title> 
</head> 
<body> 
<p>This is the one and 
only paragraph . </p> 
</body> 
</html > 



DOCTYPE 



meta 



document 



character 
encoding 



head 



html 



body 



title 



"This is the one and only paragraph. 1 



84 



Chapter 6: Browser and Document Objects 



FIGURE 6-6 



Inserting an element into a text node. 



<!D0CTYPE . ..> 
<html> 
<head> 
<meta . . . > 
<titl eX/titl e> 
</head> 
<body> 
< p > T h i s is the <em>one 
and only</em> 
paragraph . </p> 
</body> 
</html > 



document 



DOCTYPE 



html 



head 



body 



meta 



character 
encoding 



title 



"This is the " 



em 

IE 



' paragraph.' 



"one and only" 



Object References 

After a document is loaded into the browser, all of its objects are safely stored in memory in the con- 
tainment hierarchy structure specified by the browser's DOM. For a script to control one of those 
objects, there must be a way to communicate with an object and find out something about it (such 
as "Hey, Mr. Text Field, what did the user type?")- To let your scripts talk to an object, you need a 
way to refer to that object. That is precisely what an object reference in a script does for the browser. 

Object naming 

The biggest aid in creating script references to objects is assigning a name to every scriptable object 
in your HTML. In the W3C DOM (and current HTML specification), the way to assign a name to an 
element is by way of the i d attribute. This attribute is optional, but if you plan to use scripts to access 
an element in the page, it is most convenient to assign a name to that element's i d attribute directly 
in the HTML code. Here are some examples of i d attributes added to typical tags: 

<p id="fi rstParagraph"> 

<img id="logo-l" s rc=" i mages / 1 ogo . j pg" al t="Corporate Logo") 

<div cl ass="draggabl e" i d="puzzl e_pi ece"> 
The only rules about object IDs (also called identifiers) art that they: 

• May not contain spaces 

• May not contain punctuation except for the underscore, hyphen, period, and colon characters 



85 



Part II: JavaScript Tutorial 



• Must be inside quotes when assigned to the i d attribute 

• Must not start with a numeric character 

• May not occur more than once in the same document 

Think of assigning IDs as the same way as sticking name tags on everyone attending a conference 
meeting. To find a particular conference attendee whose name you know, you could wait at the 
entrance and scan each name tag until you find the name you're looking for, or you could bump 
around the attendees at random in the hope that you'll find a known name. But it would be more 
efficient if you had a way to target an attendee by name immediately — such as broadcasting the 
name on the public address system to the whole crowd. 

Referencing a particular object 

The W3C DOM provides that kind of instant access to any named element in the document. Here is 
the syntax you will use frequently in your browser scripting: 

w indow. document. getElement By I d ( " el emeriti D" ) 

You substitute the ID of the element you wish to reference for el ementlD. For example, if you want 
to reference the paragraph element whose ID is fi rstParagraph, the reference would be 

window. document. get El ementBy I d ("fi rstParagraph") 

JavaScript allows us to shorten this by omitting the wi ndow reference, so we often use this briefer 
form: 

doc ument.getElement By Id ( " f i rstParagraph") 

Be careful! JavaScript is case sensitive. Be sure that you use uppercase for the three uppercase letters 
in the command and a lowercase d at the end, and that you spell the ID itself accurately as well. 

The getEl ementById( ) command belongs to the document object, meaning that the entire doc- 
ument's collection of elements is subject to this instantaneous search for a matching ID. The dot — a 
traditional period character — is the JavaScript way of indicating that the item to the left of the dot 
(the document object here) has the item to the right of the dot (get El ementBy Id ( ) here) as a 
resource to call upon whenever needed. Each type of object has a list of such resources, as you'll see 
in a moment (and as summarized in Appendix A). 

id and name Attributes 

Prior to the HTML 4.0 specification's introduction of the id attribute, scripts could access a handful 
of elements that also supported the name attribute. Elements supporting the name attribute are 
predominantly related to forms, images, and frames. You will see how name attributes work in forms 
in Chapter 11, "Forms and Form Elements." In fact, most browsers still require the name attribute for 
forms and form controls (text fields, buttons, and select lists) for their data to be submitted to a server. It 
is permissible to assign the same identifier to both the i d and name attributes of an element, and, in 
fact, in XHTML it is recommended that an i d and name assigned to the same element have the same 
value. For example: 

<input type="text" i d="f i rstname" name="f i rstname" /> 



86 



Chapter 6: Browser and Document Objects 



Node Terminology 

W3C DOM terminology uses metaphors to assist programmers in visualizing the containment hierar- 
chy of a document and its content. One concept you should grasp early in your learning is that of a 
node; the other concept is the family relationship among objects in a document. 

About nodes 

Although the English dictionary contains numerous definitions of node, the one that comes closest 
to its application in the W3C DOM implies a knob or bump on a tree branch. Such nodules on a 
branch usually lead to one of two things: a leaf or another branch. A leaf is a dead end in that no 
further branches emanate from the leaf; the branch kind of node leads to a new branch that can itself 
have further nodes, whether they be leaves or more branches. When you define the structure of an 
HTML document, you also define a node structure (also called a node tree) in which the placement of 
branches and leaves depends entirely on your HTML elements and text content. 

In the W3C DOM, the fundamental building block is a simple, generic node. But inside an HTML 
document, we work with special kinds of nodes that are tailored to HTML documents. The two types 
of nodes that scripts touch most often are element nodes and text nodes. These node types correspond 
exactly to HTML elements and the text that goes between an element's start and end tags. You've been 
working with element and text nodes in your HTML authoring, and you may not have even known it. 

Look again at the simple document we've just assembled, along with its containment hierarchy dia- 
gram in Figure 6-7. All of the boxes representing HTML elements (html , head, body, p, and em) are 
element nodes; the three boxes containing the actual text that appears in the rendered document are 
text nodes. You saw in the transition from one long text node (Figure 6-5) to the insertion of the em 
element (Figure 6-6) that the long text node divided into three pieces. Two text node pieces stayed in 
the same position in the hierarchy relative to the containing p element. We inserted the new em ele- 
ment into the tree between the two text nodes and shifted the third text node one level away from the 
p element. 



Parents and children 

Looking more closely at the p element and its content in Figure 6-7, you can see that element has 
three child nodes. The first and last are of the text node type, whereas the middle one is an element 
node. When an element contains multiple child nodes, the sequence of child nodes is entirely depen- 
dent upon the HTML source code order. Thus, the first child node of the p element is the text node 
containing the text "This is the ". The em element has a single child text node as its sole descendant. 

Element node children are not always text nodes; neither do branches always end in text nodes. 
In Figure 6-7, the html element has two child nodes, both of which are element nodes; the 
body element has one child node, the p element. A tag in the HTML indicates an element 
node, whether or not it has any child nodes. By contrast, a text node can never contain another 
node; it's one of those dead-end leaf type of nodes. 

Notice that a child node is always contained by one element node. That container is the parent node 
of its child or children. For example, from the point of view of the em element node, it has both one 
child (a text node) and one parent (the p element node). A fair amount of W3C DOM terminology 
(which you'll meet in Chapter 25, "Document Object Model Essentials") concerns itself with assist- 
ing scripts starting at any point in a document hierarchy and obtaining a reference to a related node 
if necessary. For instance, if a Dynamic HTML script wants to modify the text inside the em element 



87 



Part II: JavaScript Tutorial 



of Figure 6-7, it typically would do so by starting with a reference to the em element via the docu- 
ment.getElementById( ) command (assuming that the em element has an ID assigned to it) and 
then modifying the element's child node. 



FIGURE 6-7 



A simple HTML document node tree. 



.> 



. .> 

;/titl e) 



<!D0CTYPE 
<html> 
<head> 
<meta 
< t i 1 1 e 
</head> 
<body> 
<p>This is the <em>one 
and only</em> 
paragraph . </p> 
</body> 
</html > 



document 



DOCTYPE 



html 



head 



body 



meta 



character 
encoding 



title 



"This is the " 



' paragraph.' 



"one and only" 



In case you're wondering, the document object at the top of the node tree is itself a node. 
Its place in the tree is special and is called simply the document node. Each loaded HTML 
document contains a single document node, and that node becomes the scripter's gateway to 
the rest of the document's nodes. It's no accident that the syntax for referencing an element 
node — document . get El ementESyId( ) — begins with a reference to the document object. 



What Defines an Object? 

When an HTML tag defines an object in the source code, the browser creates a slot for that object 
in memory as the page loads. But an object is far more complex internally than, say, a mere number 
stored in memory. The purpose of an object is to represent some thing. In the browser and its DOM 
the most common objects are those that correspond to elements, such as a text input form field, a 
table element, or the entire rendered body of the document. Outside the pared-down world of the 
DOM, an object can also represent abstract entities, such as a calendar program's appointment entry 
or a layer of graphical shapes in a drawing program. It is common for your browser scripts to work 
with both DOM objects and abstract objects of your own design. 

Every type of DOM object is unique in some way, even if two or more objects look identical to you 
in the browser. Three very important facets of an object define what it is: what it "looks" like, how 



88 



Chapter 6: Browser and Document Objects 



it behaves, and how scripts control it. Those three facets are properties, methods, and events (also 
known as handlers). They will play key roles in your future DOM scripting efforts. The Quick Ref- 
erence in Appendix A summarizes the properties, methods, and events for each object in the object 
models implemented in the various browser generations. 

Properties 

Any physical object you hold in your hand has a collection of characteristics that defines it. A com, 
for example, has shape, diameter, thickness, color, weight, embossed images on each side — and any 
number of other attributes that distinguish it from, say, a feather. Each of those features is called a 
property. Each property has a value of some kind attached to it (even if the value is empty or null). 
For example, the shape property of a coin might be circle — in this case, a text value. By contrast, 
the denomi nati on property would most likely be a numeric value. 

You may not have known it, but if you've written HTML for use in a scriptable browser, you have 
set object properties without writing one iota of JavaScript. Tag attributes are the most common way 
to set an HTML element object's initial properties. For example, the following HTML tag defines an 
input element object that assigns four property values: 

<input type="button" i d = " c 1 i c k e r " name="cl i cker" value="Hit Me..."> 

In JavaScript parlance, then, the type property holds the word button; the i d and name properties 
hold the same word, clicker; and the val ue property is the text that appears on the button label, Hit 
Me . . . .In truth, a button input element has more properties than just these, but you don't have to 
set every property for every object. Most properties have default values that are automatically assigned 
if nothing special is set in the HTML, or later from a script. 

The contents of some properties can change after a document has loaded and the user interacts with 
the page. Consider the following text input tag: 

<input type="text" i d = "donati on" name=" donat i on " va 1 ue=" $0 . 00 " > 

The i d and name properties of this object are the same word: donati on . When the page loads, the 
text of the value attribute setting is placed in the text field — the automatic behavior of an HTML 
text field when the value attribute is specified. But if a user enters some other text into the text field, 
the val ue property changes — not in the HTML, but in the memory copy of the object model that 
the browser maintains. Therefore, if a script queries the text field about the content of the val ue 
property, the browser yields the current setting of the property — which isn't necessarily the one 
specified by the HTML. 

To gain access to an object's property, you use the same kind of dot-notation addressing scheme you 
saw earlier for objects. A property is a resource belonging to its object, so the reference to it consists of 
the reference to the object plus one more extension naming the property. Therefore, for the button 
and text object tags just shown, references to various properties are 

docume nt. get El ement By Id ( " clicker"). name 
docume nt.getElement By Id ( " clicker"). value 
docume nt.getEl ement By Id(" entry"). val ue 



89 



Part II: JavaScript Tutorial 



Tip 

JavaScript will fail or "abort" if it tries to reference the property of a non-existent element. Therefore, a safer, 
more bulletproof way of referencing these properties is to first test for the existence of the object: 

var oClicker = document . getEl ementByldC "cl i cker" ) ; 
if (oClicker) var sName = oCl i cker . name ; 

or 

var oClicker = document . getEl ementByldC "cl i cker" ) ; 

if ( ! oCl i cker ) return ; 
var sName = oCl i cker . name ; ■ 

You might wonder what happened to the wi ndow part of the reference. It turns out that there can be 
only one document contained in a window, so references to objects inside the document can omit the 
wi ndow portion and start the reference with document. You cannot omit the document object from 
the reference, however. 

Methods 

If a property is like a descriptive adjective for an object, a method is a verb. A method is all about 
action related to the object. A method does something either to the object or with the object that 
affects other parts of a script or document. Methods are commands of a sort whose behaviors are tied 
to a particular object. 

Internet Explorer References 

Before the W3C DOM came into existence, Microsoft had created its own way of referencing element 
objects by way of their i d attributes. You will find many instances of this syntax in existing code that has 
been written only for Internet Explorer 4 or later. The syntax uses a construction called document . a 1 1 . 
Although there are a few different ways to use this construction, the most commonly applied way is to 
continue the dot notation to include the ID of the element. For example, if a paragraph element's ID is 
my Paragraph, the IE-only reference syntax is 

document. all .my Paragraph 

You can also omit the lead-in parts of the reference and simply refer to the ID of the element: 

my Paragraph 

Be aware, however, that none of these approaches is supported in the W3C DOM standard. Both 
the IE-specific and W3C DOM reference syntax styles are implemented in IE5 or later. Also the 
document .all .el ementld syntax cannot tolerate some of the valid HTML ID characters, such as 
hyphen, colon, and period, because JavaScript would interpret them as its own syntax. 

Although it's important to be familiar with document .all in order to make sense of legacy code, you 
should stick to W3C DOM methods such asgetElementByldO in your own code to be compatible 
with forward-looking modern browsers. 



90 



Chapter 6: Browser and Document Objects 



Note 



Note that the document.all syntax cannot tolerate any hyphens, colons, or periods in the ID. Although these are 
valid HTML IDs 



the resulting document.all expressions would cause JavaScript to give erroneous results or crash: 



Using the modern standard getElementByldO is safer because the ID is always enclosed in 
quotation marks. ■ 



An object can have any number of methods associated with it (including none at all). To set a method 
into motion (usually called invoking a method), a JavaScript statement must include a reference to it, 
via its object, with a pair of parentheses after the method name, as in the following examples: 

var oForm = document . get El ementBy Id ( "order Form" ) ; 
oForm. submi t( ) ; 

var oEntry = document . getEl ementBy Id( "entry" ) ; 
oEntry . focus ( ) ; 

The first is a scripted way of sending a form (named orderForm) to a server. The second gives focus 
to a text field named entry. 

Sometimes a method requires that you send additional information with it so that it can do its job. 
Each chunk of information passed with the method is called a parameter or argument (you can use the 
terms interchangeably). The document . getEl ementBy Id( ) method is one that requires a param- 
eter: the identifier of the element object to be addressed for further action. This method's parameter 
must be in a format consisting of straight text, signified by the quotes around the identifier. 

Some methods require more than one parameter. If so, the multiple parameters are separated by com- 
mas. For example, modern browsers support a wi ndow object method that moves the window to a 
particular coordinate point onscreen. A coordinate point is defined by two numbers that indicate the 
number of pixels from the left and top edges of the screen where the top-left corner of the window 
should be. To move the browser window to a spot 50 pixels from the left and 100 pixels from the 
top, the method is 

window.moveTo(50,100) 
As you learn more about the details of JavaScript and the document objects you can script, pay close 
attention to the range of methods defined for each object. They reveal a lot about what an object is 
capable of doing under script control. 



One last characteristic of a DOM object is the event. Events are actions that take place in a document, 
usually as the result of user activity. Common examples of user actions that trigger events include 



my 
my 
my 



paragraph 
paragraph 
paragraph 



document.all .my-paragraph 
document.all . my . pa ragraph 
document.all . my : pa ragraph 



Events 



91 



Part II: JavaScript Tutorial 



clicking a button or typing a character in a text field. Some events, such as the act of loading a doc- 
ument into the browser window or experiencing a network error while an image loads, are not so 
obvious. 

Almost every DOM object in a document receives events of one kind or another — summarized for 
your convenience in the Quick Reference of Appendix A. Your job as scripter is to write the code that 
tells an element object to perform an action whenever the element receives a particular type of event. 
The action is simply executing some additional JavaScript code. 

A simple way to begin learning about events is to apply one to an HTML element. Listing 4-1 shows a 
very simple document that displays a single button and a script that applies one event handler to the 
button. The event's name consists of the type of event (for example, click) preceded by the preposi- 
tion on (as in, "on receiving the cl i ck event ... ": oncl i ck). 



LISTING 6-1 



A Simple Button with an Event Handler 

HTML: jsb-06-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v = "content-type" content="text/html ;charset=utf -8"> 
<title>A Simple Button with an Event Handl er</ti tl e> 
<script type=" text/javascript" src="jsb-06-01.js"X/script> 

</head> 

<body> 

<form action=""> 
< d i v > 

<button i d="cl i cker">Cl i ck me</button> 
</di v> 
</f orm> 
</body> 
</html > 

JavaScript: jsb-06-01.js 

// tell the browser to run this script when the page has finished loading 
wi ndow . onl oad = applyBehavi or ; 

// apply behavior to the button 
function applyBehavior() 

{ 

// ensure a DOM-aware user agent 
if ( document . get El ementBy I d ) 

{ 

// point to the button 

var oButton = document . getEl ementById( ' cl i cker ') ; 

// if it exists, apply behavior 
if (oButton) 

{ 



92 



Chapter 6: Browser and Document Objects 



oButton . oncl i ck = behave; 

} 

} 

} 

// what to do when the button is clicked 
function behave(evt) 

{ 

alert( 'Ouch ! ' ) ; 

) 



When the browser loads the HTML page, it also loads the linked JavaScript file, compiles it, and 
begins to execute its instructions. In this case, the only instruction it will actually execute immediately 
is the window. onload statement because all the other statements are inside functions and won't 
execute until the functions are called by name. Only when the HTML page has finished loading (and 
when its DOM has been completely built) will our function applyBehavior( ) run. If the JavaScript 
interpreter that's running is aware of the DOM method getEl ementById( ), the function uses it to 
look up the element with the ID of cl i cker. If found, it applies the onclick behavior to the but- 
ton, telling it to execute the function behave ( ) when clicked. When the user clicks the button, the 
behave( ) function issues an alert (a popup dialog box) that says, "Ouch!" 

Cross-Reference 

You will learn about other ways to connect scripting instructions to events in Chapter 25, "Document Object 
Model Essentials," and Chapter 32, "Event Objects." ■ 

Exercises 



1 . Which of the following applications are well suited to client-side JavaScript? Why or why not? 

a. Product catalog page that lets visitors view the product in five different colors 

b. A counter that displays the total number of visitors to the current page 
C. Chat room 

d. Graphical Fahrenheit-to-Celsius temperature calculator 

e. All of the above 

f . None of the above 

2. Which of the following element IDs are valid in HTML? For each one that is invalid, explain 
why. 

a. I astName 

b. company_name 

c. IstLi neAddress 

d. zip code 

e. today ' s_date 

f. now:you-hear.this 



93 



Part II: JavaScript Tutorial 



3. Using the diagram from Figure 6-7 for reference, draw a diagram of the object model contain- 
ment hierarchy that the browser would create in its memory for the following HTML. Write the 
script reference to the first paragraph element using W3C DOM syntax. 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 

<ti tl e>Sea rch Form</ti tl e> 

</head> 

<body> 

<p i d=" 1 ogoPa r " ><i mg s rc=" i mages /I ogo . j pg " height="90" width="300" 

al t=" Logo" ></p> 
<d i v i d=" sea rch Form" > 

<form acti on = "cgi -bi n/search . pi " method="post"> 
<di v> 

< 1 a be 1 for="searchText">Search for:</label> 

<input type="text" i d="searchText" name="searchText"> 

<input type=" submi t " val ue="Search"> 

</div> 

</f orm> 

</di v> 

</body> 

</html > 

4. Describe at least two characteristics that a text node and an element node have in common; 
describe at least two characteristics that distinguish a text node from an element node. 

5. Write the HTML and JavaScript for a button input element named H i , whose visible label 
reads Howdy, and whose action upon being clicked displays an alert dialog box that says, 
Hello to you , too ! 



94 



CHAPTER 



Scripts and HTML 
Documents 




Chapter 4, "JavaScript Essentials," covered many of the basics of how 
to combine JavaScript with HTML documents. This chapter's tutorial 
reviews how scripts are linked to HTML documents and what comprises 
a script statement. You also see how script statements can run when the 
document loads or in response to user action. Finally, you find out where script 
error information may be hiding. 



Connecting Scripts to Documents 

We use the script element to tell the browser to treat a segment of 
text as script and not as HTML. Whether our script is an external file 
linked to the HTML document or embedded directly in the page itself, the 
<scri pt> . . . </scri pt> tag set encapsulates the script. 

Depending on the browser, the <scri pt> tag has a variety of attributes you 
can set that govern the script. One attribute, type, advises the browser to treat 
the code within the tag as JavaScript. Some other browsers accept additional lan- 
guages (such as Microsoft's VBScript in Windows versions of Internet Explorer). 
The following setting is one that all modern scriptable browsers accept: 

<script type=" text/ j a vascri pt " ...>... <scri pt> 

Be sure to include the ending tag for the script. Your JavaScript program code 
goes either into an external file specified in the s rc attribute: 

<script type=" text/javascript" src="exampl e . js "Xscri pt> 



IN THIS CHAPTER 



Where to place scripts in 
HTML documents 

What a JavaScript statement is 

What makes a script run 

Viewing script errors 



or between the two tags: 

<script type="text/javascript"> 

one or more lines of JavaScri pt code here 
</scri pt> 



95 



Part II: JavaScript Tutorial 



If you forget the closing script tag, the script may not run properly, and the HTML elsewhere in the 
page may look strange. 

The Old language Attribute 

Another <scri pt> tag attribute, 1 anguage, used to be the way to specify the scripting language for 
the enclosed code. That attribute allowed scripters to specify the language version. For example, if 
the scripts included code that required JavaScript syntax available only in version 4 browsers (which 
implemented JavaScript version 1 .2), the <scri pt> tag used to be written as follows: 

<script language="JavaScriptl.2">. . .</script> 

The language attribute was never part of the HTML 4.0 specification and is now falling out of favor. If 
W3C validation is one of your development concerns, you should be aware that the language attribute 
does not validate in strict versions of HTML 4.01 or XHTML 1 .0. Older browsers that do not know the 
type attribute automatically default to JavaScript anyway. Use only the type attribute. 



Tag positions 

Where do these tags go within a document? The answer is anywhere they're needed in the document. 
Most of the time, it makes sense to include the tags nested within the <head>. . .</head> 
tag set; other times, it is essential that you drop the script into a very specific location in the 
<body> . . . </body> section. 

In the following three listings, we demonstrate — with the help of a skeletal HTML document — 
some of the possibilities of <scri pt> tag placement. Later in this lesson, you see why scripts 
may need to go in different places within a page, depending on the scripting requirements. In 
each example, we show two scri pt tags - one a link to an external script and one for internal 
embedded scripting - just to show you how they both appear. In practice, it's most likely that you 
will consistently link only to external scripts. 

Listing 7-1 shows the outline of what may be the most common position of a <script> tag set 
in a document: in the <head> tag section. Typically, the head is a place for tags that influence 
non-content settings for the page — so-called HTML directive elements, such as <meta> tags and 
the document title. It turns out that this is also a convenient place to plant scripts that are called in 
response to a page load or a user action. 



LISTING 7-1 



Scripts in the head 

<html > 
<head> 

<title>A Document</ti tl e> 

<script type=" text/javascript" src="exampl e. js "X/scri pt> 
<script type="text/javascript"> 
//script statement ( s ) here 



96 



Chapter 7: Scripts and HTML Documents 



</scri pt> 
</head> 
<body> 
</body> 
</html > 



On the other hand, if you need a script to run as the page loads so that the script generates content 
in the page, the script goes in the <body> portion of the document, as shown in Listing 7-2. 



LISTING 7-2 



A Script in the body 

<html > 
<head> 

<title>A Document</ti tl e> 
</head> 
<body> 

<script type=" text/javascript" src="exampl e . js "X/scri pt> 
<script type="text/javascript"> 
//script statement ( s ) here 

</scri pt> 
</body> 
</html > 



It's also good to know that you can place an unlimited number of <scri pt> tag sets in a document. 
For example, Listing 7-3 shows a script in both the head and body portions. This document needs 
the body script, perhaps to create some dynamic content as the page loads, but the document also 
contains a button that needs a script to run later. That script is stored in the head portion. 



LISTING 7-3 



Scripts in the head and body 

<html > 
<head> 

<title>A Document</ti tl e> 

<script type=" text/javascript" src="exampl e . js "X/scri pt> 
<script type="text/javascript"> 
//script statement ( s ) here 

</scri pt> 
</head> 
<body> 

<script type=" text/javascript" src="example.js "X/scri pt> 



continued 



97 



Part II: JavaScript Tutorial 



LISTING 7-3 



(continued) 



<script type="text/javascript"> 
//script statement ( s ) here 



</scri pt> 
</body> 
</html > 



Handling non-JavaScript browsers and XHTML 

Only browsers that include JavaScript know to interpret the lines of code between the 
<script>. . .</script> tag pair as script statements rather than HTML text for display in 
the browser. This means that a pre-JavaScript browser or a simplified browser in a cell phone would 
not only ignore the tags, but also treat the JavaScript code as page content. The results can be 
disastrous to a page. 

On the other hand, you don't have to worry about non-JavaScript browsers trying to execute exter- 
nally linked scripts. That's one of the advantages of linking rather than embedding your scripts. The 
problem only arises when JavaScript code is embedded in the HTML document. 

You can reduce the risk of older, non-JavaScript browsers displaying the script lines by enclosing the 
script lines between HTML comment symbols, as shown in Listing 7-4. Most nonscriptable browsers 
ignore the content between the < ! - - and -> comment tags, whereas scriptable browsers ignore the 
opening comment symbol when it appears inside a <scri pt> tag set. 



LISTING 7-4 



Hiding Scripts from Most Old Browsers 

<script type="text/javascript"> 

<!-- 

//script statement ( s ) here 

II --> 
</scri pt> 



The odd construction right before the ending script tag needs a brief explanation. The two forward 
slashes are a JavaScript comment symbol. This symbol is necessary because JavaScript otherwise tries 
to interpret the components of the ending HTML symbol (- ->). Therefore, while the forward slashes 
tell JavaScript to skip the line entirely, a non-scriptable browser simply treats those slash characters as 
part of the entire HTML comment to be ignored. 

Although it's no longer really necessary to hide JavaScript in this way from older browsers, there are 
instances when a different type of hiding may be required. XML is more frequently being used to feed 
content to the browser, and often this is done using XHTML. In the XML world, all special charac- 
ters need to be enclosed in a CDATA section, or else the file may be parsed incorrectly; at the very 
least, it will fail validation. Again, the trick is to enclose your script, but this time it will look like 



98 



Chapter 7: Scripts and HTML Documents 



Listing 7-5. You'll notice again that immediately before the closing script tag the JavaScript comment 
hides the closing of the CDATA section from JavaScript itself. 



LISTING 7-5 



Hiding Scripts From XML Parsers 

<script type="text/javascript"> 
<! [CDATA[ 

//script statement ( s ) here 

//]]> 
</scri pt> 



Despite the fact that these techniques are often called script hiding, they do not conceal the scripts 
from human readers. All client-side JavaScript scripts are part of, or accompany, the HTML document, 
and they download to the browser just like all the other assets that make up the page. You can view 
the JavaScript source as easily as you can view the HTML document source. Do not be fooled into 
thinking that you can hide your scripts from prying eyes. Some developers obfuscate their scripts by 
removing all carriage returns and using nonsensical variable and function names, but this only slows 
down (and doesn't stop) any inquisitive visitor from reading and understanding the code. 

Since it's not possible to truly hide your JavaScript programming from the public, you might as well 
flaunt it: sign the scripts you're proud of, include a copyright or Creative Commons notice of author- 
ship in script comments, and encourage people who admire the script to come to you for more. 



JavaScript Statements 

Virtually every line of code in an externally linked file or that sits within a <script>. . .</script> 
tag pair is a JavaScript statement (except for HTML comment tags). To be compatible with the habits of 
experienced programmers, JavaScript accepts a semicolon at the end of every statement (the computer 
equivalent of a period at the end of a sentence). This semicolon is optional, but we strongly recom- 
mend that you use it consistently to avoid ambiguity. The carriage return at the end of a statement 
suffices for JavaScript to know that the statement has ended. It is possible, however, that in the future 
the semicolon will be required, so it's a good idea to get into the semicolon habit now. 

A statement must be in the script for a purpose. Therefore, every statement does something relevant 
to the script. The kinds of things that statements do are 

• Define or initialize a variable 

• Assign a value to a property or variable 

• Change the value of a property or variable 

• Define or invoke an object's method 

• Define or invoke a function routine 

• Make a decision 



99 



Part II: JavaScript Tutorial 



If you don't yet know what all of these things mean, don't worry; you will, by the end of this tutorial. 
The point we want to stress is that each statement contributes to the scripts you write. The only 
statement that doesn't perform any explicit action is the comment. A pair of forward slashes (no space 
between them) is the most common way to include a single-line comment in a script: 

// this is a one-line comment 

var a = b; // this comment shares a line with an active statement 
Multiple-line comments can be enclosed in slash-asterisks: 

/* 

Any number of lines are comments if they are 
bracketed by slash-asterisks 

*/ 

You add comments to a script for the benefit of yourself and other human readers. They usually 
explain in plain language what a statement or group of statements does. The purpose of including 
comments is to remind you how your script works six months from now, or to help out another 
developer who needs to read your code. 

When Script Statements Execute 

Now that you know where scripts go in a document, it's time to look at when they run. Depending 
on what you need a script to do, you have four choices for determining when a script runs: 

• While a document loads 

• Immediately after a document loads 

• In response to user action 

• When called upon by other script statements 

The determining factor is how the script statements are positioned in a document. 

While a document loads: immediate execution 

Listing 7-6 is a variation of your first script from Chapter 5, "Your First JavaScript Script." In 
this version, the script writes the current date and time to the page while the page loads. The 
document, wr i te ( ) method is a common way to write dynamic content to the page during loading. 
We call the kinds of statements that run as the page loads immediate statements. Care must be taken 
when you code scripts using document . wri te( ). Once the page completes loading, any further 
document. write ( ) statements create a new page, overwriting all the content you have carefully 
written. 



LISTING 7-6 



HTML Page with Immediate Script Execution 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Date & Time: Immediate Executi on</ti tl e> 



100 



Chapter 7: Scripts and HTML Documents 



</head> 
<body> 

<hl>Date & Time: Immediate Executi on</hl> 
< p > 1 1 is currently <span i d = " output " > 
<script type="text/javascript"> 

<!-- hide from old browsers 

va r oNow = new Date ( ) ; 

document .write(oNow.toLocal eStri ng ( ) ) ; 

// end script hiding --> 
</scri pt> 
</span> . </p> 
</body> 
</html > 



In recent years, the use of document .wri te( ) has become mildly controversial. At the very least, 
it encourages bad structure in your document, mixing script with HTML. Good structure cleanly 
separates style (style sheets) and behavior (JavaScript) from the HTML markup. One issue with 
document .wri te( ) centers around the increased use of XML to feed content to the browser. XML 
documents must be well-formed. If a document .wri te( ) statement closes an element opened 
outside of it, or opens a new element, the XML document will fail to load because the browser will 
perceive it as malformed. 

Another issue with document .wri te( ) centers around the DOM, especially with XHTML docu- 
ments (which are served as XML) . The use of document. write( ) means that the content will not 
be included in the DOM. The very important short story is that you will not be able to further manip- 
ulate such content with your JavaScript programs, limiting your dynamic response to the visitor's 
actions on your web page. This is an interesting conundrum because you might often choose to use 
document . wri te ( ) , as we do in several examples in this book, to provide dynamic content, based 
on the browser environment, as the page loads. 



Deferred scripts 

The other three ways that script statements run are grouped together into what we call deferred scripts. 
To demonstrate these deferred script situations, we must introduce you briefly to a concept covered 
in more depth in Chapter 9, "Programming Fundamentals, Part II": the function. A junction defines a 
block of script statements summoned to run some time after those statements load into the browser. 
Functions are clearly visible inside a <script> tag because each function definition begins with the 
word f uncti on followed by the function name (and parentheses). After a function is loaded into 
the browser (commonly in the head portion so that it loads early), it stands ready to run whenever 
called upon. 

Run after loading 

One of the most common times a function is called on to run is immediately after a page loads. 
Scripts using industry-standard DOM methods would fail if we attempted to operate on page elements 
before they appeared in the DOM, so we ask the browser to run the script only after the page has 
finished loading. The wi ndow object has an event handler property called onl oad. Unlike most 
event handlers, which are triggered in response to user action (for example, clicking a button), the 



101 



Part II: JavaScript Tutorial 



window's onload event handler fires the instant that all of the page's components (including images, 
Java applets, and embedded multimedia) are loaded into the browser. 

There are two cross-browser ways to connect the onl oad event handler to a function: via an 
object event property or an HTML event attribute. The object event property we prefer is shown in 
Listing 7-6. The assignment of the event handler is executed in immediate mode and attaches the 
desired function call to the load event of the wi ndow object. At this early point in page rendering, 
only the wi ndow object can be guaranteed to exist in the DOM. 

In old-school web development, the wi ndow. onload event assignment was written right into the 
HTML, with the <body> element standing in to represent the window. Therefore, you can include the 
onl oad event attribute in the <body> tag, as shown in Listing 7-7. Recall from Chapter 6, "Browser 
and Document Objects," that an event handler can run a script statement directly. However, if the 
event handler must run several script statements, it is usually more convenient to put those statements 
in a function definition and then have the event handler invoke that function. That's what happens 
in Listing 7-7: When the page completes loading, the onl oad event handler triggers the done( ) 
function. That function (simplified for this example) displays an alert dialog box. 



LISTING 7-7 



Running a Script from the onload Event Handler 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v = "content-type" content="text/html ;charset=utf -8"> 
<title>An old-school HTML-based onload scri p t < / 1 i tl e> 
<script type="text/javascript"> 

functi on done( ) 

{ 

alert("The page has finished loading."); 

} 

</scri pt> 
</head> 

<body onl oad="done( ) "> 

<hl>An old-school HTML-based onload script</hl> 

<p>Here is some body text.</p> 
</body> 
</html > 



Don't worry about the curly braces or other oddities in Listing 7-7 at this point. Focus instead on the 
structure of the document and the flow. The entire page loads without running any script statements, 
although the page loads the d o n e ( ) function in memory so that it is ready to run at a moment's 
notice. After the document loads, the browser fires the onl oad event handler, which causes the 
done ( ) function to run. Then the user sees the alert dialog box. 

Although the HTML event attribute approach dates back to the earliest JavaScript browsers, the trend 
these days is to separate HTML markup from specifics of style (style sheets) and behavior (scripts). 
To the scripter's rescue come the equivalent event handler properties of objects. To get the onl oad 



102 



Chapter 7: Scripts and HTML Documents 



attribute out of the <body> tag, you can instead assign the desired JavaScript function to the object's 
event as a property, as in: 

window. onload = done; 

Such statements typically go near the end of scripts in the head portion of the document. Note, too, 
that in this version, the right side of the statement is merely the function's name, with no quotes 
or parentheses. Because it is easier to learn about event handlers when they're specified as HTML 
attributes, most examples in this tutorial continue with that approach. We needed to show you the 
property version, however, because you will see a lot of real-life code using that format. 

Run by user 

Getting a script to execute in response to a user action is very similar to the preceding example for 
running a deferred script right after the document loads. Commonly, a script function is defined in the 
head portion, and an event handler in, say, a form element calls upon that function to run. Listing 
7-8 includes a script that runs when a user clicks a button. 



LISTING 7-8 



Running a Script from User Action 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; cha rset=utf -8"> 
<title>An onclick sen p t < / 1 i tl e> 
<script type="text/javascript"> 

function alertllserO 

{ 

alertC'Ouch!"); 

} 

</scri pt> 
</head> 
<body> 

Here is some body text. 

<f orm> 

<input type="text" name="entry "> 
<input type="button" name="oneButton" 

value="Press Me!" oncl i ck="al ertllser( ) "> 

</f orm> 
</body> 
</html > 



Not every object must have an event handler defined for it, as shown in Listing 7-8 — only the ones 
for which scripting is needed. No script statements execute in Listing 7-8 until the user clicks the 



103 



Part II: JavaScript Tutorial 



button. The alertUserO function is defined as the page loads, and it waits to run as long as the 
page remains loaded in the browser. If it is never called upon to run, there's no harm done. 

Called by another function 

The last scenario for when script statements run also involves functions. In this case, a function is 
called upon to run by another script statement. Before you see how that works, it helps to read the 
next lesson, Chapter 8, "Programming Fundamentals, Part I." Therefore, we will hold off on this 
example until later in the tutorial. 

Viewing Script Errors 

In the early days of JavaScript in browsers, script errors displayed themselves in very obvious dialog 
boxes. These boxes were certainly helpful for scripters who wanted to debug their scripts. However, 
if a bug got through to a page served up to a nontechnical user, the error alert dialog boxes were not 
only disruptive, but also scary. To prevent such dialog boxes from disturbing unsuspecting users, the 
browser makers tried to diminish the visual impact of errors in the browser window. Unfortunately 
for scripters, it is often easy to overlook the fact that your script contains an error because the error 
message is not so obvious. 

Not only does each browser have a different way of displaying error messages, but the display can 
differ from version to version. The method to display errors in each of the major browsers is covered 
in the section "Error Message Notification" in Chapter 48, "Debugging Scripts" on the CD-ROM. While 
you need to read that section before testing your code, we've included a sample error dialog box as it 
appears in IE5+ (see Figure 7-1) and one as it appears in Mozilla 1.4+ (see Figure 7-2). Keep in mind 
that script-error dialog boxes are not necessarily displayed by default in these and other browsers. You 
have to train yourself to monitor the status bar when a page loads and after each script runs. 



FIGURE 7-1 



The expanded IE error dialog box. 



.' iilimilf nfjjul 



I OK ") |HjUfcnO,.:. 




Understanding error messages and doing something about them is a very large subject, the complete 
discussion of which is in reserved for Chapter 48. During this tutorial, however, you can use the error 
messages to see whether you mistyped a script from a listing in the book. 



104 



Chapter 7: Scripts and HTML Documents 



FIGURE 7-2 



The Mozilla 1 .4 JavaScript console window. 







- -jj 


M All W E.™™ J '■ Wmi^i H*< 








a ril a Iilliul 




Uni: 36 



Scripting versus Programming 

You may get the impression that scripting is easier than programming. Scripting simply sounds eas- 
ier or more friendly than programming. In many respects, this is true. One of our favorite analogies 
is the difference between a hobbyist who builds model airplanes from scratch and a hobbyist who 
builds model airplanes from commercial kits. The "from scratch" hobbyist carefully cuts and shapes 
each piece of wood and metal according to very detailed plans before the model starts to take shape. 
The commercial kit builder starts with many prefabricated parts and assembles them into the finished 
product. When both builders are finished, you may not be able to tell which airplane was built from 
scratch and which one came out of a box of components. In the end, both builders used many of the 
same techniques to complete the assembly, and each can take pride in the result. 

Thanks to implementations of the document object model (DOM), the browser gives scripters many 
prefabricated components with which to work. Without the browser, you'd have to be a pretty good 
programmer to develop your own application from scratch that served up content and offered user 
interaction. In the end, both authors have working applications that look equally professional. 

Beyond the DOM, however, real programming nibbles its way into the scripting world. That's because 
scripts (and programs) work with more than just objects. Earlier in this lesson, we said that each state- 
ment of a JavaScript script does "something", and that "something" involves data of some kind. Data 
is the information associated with objects or other pieces of information that a script pushes around 
from place to place with each statement. 

Data takes many forms. In JavaScript, the common incarnations of data are numbers, text (called 
strings), objects (derived from the object model or created with script), and true and f al se (called 
Boolean values). 

Each programming or scripting language determines numerous structures and limits for each kind 
of data. Fortunately for newcomers to JavaScript, the universe of knowledge necessary for working 
with data is smaller than in a language such as Java or C++. At the same time, what you learn 



105 



Part II: JavaScript Tutorial 



about data in JavaScript is immediately applicable to future learning you may undertake in any other 
programming language; don't believe for an instant that your efforts in learning scripting will be 
wasted. 

Because, deep down, scripting is programming, you need to have a basic knowledge of fundamental 
programming concepts to consider yourself a good JavaScript scripter. In the next two lessons, we set 
aside most of our discussion about the DOM and focus on the programming principles that will serve 
you well in JavaScript and future programming endeavors. 



Exercises 



1 . Write the complete script tag set for a script whose lone statement is 

document. write(" Hello, world."); 

2. Build an HTML document, and include the answer to the previous question, such that the page 
executes the script as it loads. Open the document in your browser to test the results. 

3. Add a comment to the script in the previous answer that explains what the script does. 

4. Create an HTML document that displays an alert dialog box immediately after the page loads, 
and displays a different alert dialog box when the user clicks a form button. 

5. Carefully study the document in Listing 7-9. Without entering and loading the document, pre- 
dict 

a. What the page looks like without further styling 

b. How users interact with the page 

c. What the script does 

Then type the listing as shown into a text editor. Observe all capitalization and punctuation. 
Do not type a carriage return after the = sign in the upperMe function statement; let the line 
word-wrap as it does in the following listing. It's okay to use a carriage return between attribute 
name/value pairs, as shown in the first < i n p u t > tag. Save the document as an HTML file, and 
load the file into your browser to see how well you did. 



LISTING 7-9 



How Does This Page Work? 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Text Object Val ue</ti tl e> 
<script type="text/javascript"> 

f uncti on upperMe ( ) 

{ 

document . get El erne nt By Id ( "output"). value = 

document . get El erne nt By Id ( "input") .val ue.toUpperCase( ) ; 

) 



106 



Chapter 7: Scripts and HTML Documents 



</scri pt> 
</head> 

<body> 

Enter lowercase letters for conversion to uppercase : <br> 
<form name="converter"> 

<input type="text" name="i nput" id="input" 

val ue="sampl e" onchange="upperMe( ) " /Xbr /> 
<input type="text" name="output" id="output" value="" /> 
</ form) 
</body> 
</html > 



107 



Programming 
Fundamentals, Part I 




The tutorial breaks away from HTML and documents for a while, as you 
begin to learn programming fundamentals that apply to practically every 
scripting and programming language you will encounter. Here, you start 
learning about variables, expressions, data types, and operators — things that 
might sound scary if you haven't programmed before. Don't worry. With a little 
practice, you will become quite comfortable with these terms and concepts. 



What Language Is This? 

The language you're studying is called JavaScript. But the language has some 
other names that you may have heard. JScript is Microsoft's name for the 
language. By leaving out the ava, the company doesn't have to license the Java 
name from its trademark owner: Sun Microsystems. 

A standards body called ECMA (pronounced "ECK-ma") now governs the 
specifications for the language (no matter what you call it). The document that 
provides all of the details about the language is known as ECMA-262 (it's the 
262nd standard published by ECMA). Both JavaScript and JScript are ECMA-262 
compatible. Some earlier browser versions exhibit very slight deviations from 
ECMA-262 (which came later than the earliest browsers). The most serious 
discrepancies are noted in the core language reference in Part III of this book. 



IN THIS CHAPTER 



What variables are and how to 
use them 

Why you must learn how to 
evaluate expressions 

How to convert data from one 
type to another 

How to use basic operators 



Working with Information 

With rare exceptions, every JavaScript statement you write does something with 
a hunk of information — data. Data may be text information displayed 
onscreen by a JavaScript statement or the on/off setting of a radio button 
in a form. Each single piece of information in programming is also called a 
value. Outside of programming, the term value usually connotes a number of 
some kind; in the programming world, however, the term is not as restrictive. 



109 



Part II: JavaScript Tutorial 



A string of letters is a value. A number is a value. The setting of a checkbox (whether it is checked or 
not) is a value. 

In JavaScript, a value can be one of several types. Table 8-1 lists JavaScript's formal data types, with 
examples of the values you will see displayed from time to time. 



TABLE 8-1 



JavaScript Value (Data) Types 


Type 


Example 


Description 


String 


"Howdy' 


1 A series of characters inside quote marks 


Number 


4.5 


Any number not inside quote marks 


Boolean 


true 


A logical true or false 


Null 


nul 1 


Devoid of any content, but a value just the same 


Object 




A software thing that is defined by its properties and methods (arrays 
are also objects) 


Function 




A function definition 



A language that contains these few data types simplifies programming tasks, especially those 
involving what other languages consider to be incompatible types of numbers (integers versus real or 
floating-point values). In some definitions of syntax and parts of objects later in this book, we make 
specific reference to the type of value accepted in placeholders. When a string is required, any text 
inside a set of quotes suffices. 

You will encounter situations, however, in which the value type may get in the way of a smooth 
script step. For example, if a user enters a number into a form's text input field, the browser stores 
that number as a string value type. If the script is to perform some arithmetic on that number, you 
must convert the string to a number before you can apply the value to any math operations. You see 
examples of this later in this lesson. 

Variables 

Cooking up a dish according to a recipe in the kitchen has one advantage over cooking up some data 
in a program. In the kitchen, you follow recipe steps and work with real things: carrots, milk, or a 
salmon filet. A computer, on the other hand, follows a list of instructions to work with data. Even 
if the data represents something that looks real, such as the text entered into a form's input field, 
once the value gets into the program, you can no longer reach out and touch it. 

In truth, the data that a program works with is merely a collection of bits (on and off states) in your 
computer's memory. More specifically, data in a JavaScript-enhanced web page occupies parts of the 
computer's memory set aside for exclusive use by the browser software. In the olden days, program- 
mers had to know the numeric address in memory (RAM) where a value was stored to retrieve a 
copy of it for, say, some addition. Although the innards of a program have that level of complexity, 
programming languages such as JavaScript shield you from it. 



110 



Chapter 8: Programming Fundamentals, Part I 



The most convenient way to work with data in a script is to first assign the data to a variable. It's usu- 
ally easier to think of a variable as a basket that holds information. How long the variable holds the 
information depends on a number of factors. But the instant a web page clears the window (or frame), 
any variables it knows about are discarded. 

Creating variables 

You have a couple of ways to create a variable in JavaScript, but one way covers all cases properly. 
Use the var keyword, followed by the name you want to give that variable. Therefore, to declare a 
new variable called myAge, the JavaScript statement is 

var myAge; 

That statement lets the browser know that you can use that variable later to hold information or to 
modify any of the data in that variable. 

To assign a value to a variable, use one of the assignment operators. The most common one by far is 
the equal sign. For example, if you want to assign a value to the myAge variable at the same time that 
you declare it (a combined process known as initializing the variable), use that operator in the same 
statement as the var keyword: 

var myAge = 45; 

On the other hand, if you declare a variable in one statement and later want to assign a value to it, 
the sequence of statements is 



var myAge; 
myAge = 45; 

Use the var keyword for declaration or initialization — 
name in a document. 



typically only once for the life of any variable 



A JavaScript variable can hold any value type. Unlike many other languages, you don't have to tell 
JavaScript during variable declaration what type of value the variable will hold. In fact, the value type 
of a variable can change during the execution of a program. (This flexibility drives experienced pro- 
grammers crazy because they're accustomed to assigning both a data type and a value to a variable.) 

Naming variables 

Choose the names you assign to variables with care. You'll often find scripts that use vague variable 
names, such as single letters. Other than a few specific circumstances where using letters is a common 
practice (for example, using i as a counting variable in repeat loops in Chapter 9), you should use 
names that truly describe a variable's contents. This practice can help you follow the state of your data 
through a long series of statements or jumps, especially for complex scripts. 

A number of restrictions help instill good practice in assigning names. First, you cannot use any 
reserved keyword as a variable name. That includes all keywords currently used by the language 
and all others held in reserve for future versions of JavaScript. The designers of JavaScript, however, 
cannot foresee every keyword that the language may need in the future. By using the kind of single 
words that currently appear in the list of reserved keywords (see Appendix C, on the CD-ROM), you 
always run a risk of a future conflict. 

To complicate matters, a variable name cannot contain space characters. Therefore, one -word variable 
names are fine. Should your description really benefit from more than one word, you can use one of 



111 



Part II: JavaScript Tutorial 



two conventions to join multiple words as one. One convention is to place an underscore character 
between the words; the other is to start the combination word with a lowercase letter and capital- 
ize the first letter of each subsequent word within the name — referred to as CamelCase or interCap 
format. Both of the following examples are valid variable names: 

my_age 
myAge 

Our preference is for the second version; it is easier to type and easier to read. In fact, because of the 
potential conflict with future one-word keywords, using multiword combinations for variable names is 
a good idea. Multiword combinations are less likely to appear in the list of reserved words. 

Variable names have a couple of other important restrictions. Avoid all punctuation symbols except 
for the underscore character. Also, the first character of a variable name cannot be a numeral. If these 
restrictions sound familiar, it's because they're similar to those for HTML element identifiers described 
in Chapter 6. 

Expressions and Evaluation 

Another concept closely related to the value and variable is expression evaluation — perhaps the most 
important concept in learning how to program a computer. 

We use expressions in our everyday language. Remember the theme song of "The Beverly Hillbillies"?: 

Then one day he was shootin' at some food 

And up through the ground came a-bubblin' crude 

Oil, that is. Black gold. Texas tea. 

At the end of the song, you find four quite different references (crude, oil, black gold, and Texas tea). 
They all mean oil. They're all expressions for oil. Say any one of them, and other people know what 
you mean. In our minds, we evaluate those expressions to mean one thing: oil. 

In programming, a variable always evaluates to its contents, or value. For example, after assigning a 
value to a variable, such as 

var myAge = 45; 

any time the variable is used in a statement, its value (45) is automatically applied to whatever oper- 
ation that statement calls. Therefore, if you're 15 years my junior, I can assign a value to a variable 
representing your age based on the evaluated value of myAge: 

var yourAge = myAge - 15; 

The variable, yourAge, evaluates to 30 the next time the script uses it. If the myAge value changes 
later in the script, the change has no link to the yourAge variable because myAge evaluated to 45 
when it was used to assign a value to yourAge. 

Expressions in scripts 

You probably didn't recognize it at the time, but you have seen how expression evaluation 
came in handy in several scripts in previous chapters. Let's look at one in particular — from 



112 



Chapter 8: Programming Fundamentals, Part I 



Listing 5-6 — where a script writes dynamic text to the page as the page loads. Recall the second 
document . wri te ( ) statement: 

document . wri te ( " of " + navi gator . appName + "."); 



Testing JavaScript Evaluation 

You can begin experimenting with the way JavaScript evaluates expressions with the help of The 
Evaluator Jr. (see Figure 8-1), an HTML page you can find on the companion CD-ROM. (The Senior 
version is introduced in Chapter 4, "JavaScript Essentials.") Enter any JavaScript expression into the top 
text box, and either press Enter/Return or click the Evaluate button. 



FIGURE 8-1 



The Evaluator Jr. for testing expression evaluation. 



' ' The Evaluator Jr. - Mazilla Firefox 


JnJx] 


File E*t View History flookimsrtts I00I5 Help 


Ihe LiiciSurtrui Ji. 


F 


The EvnJuat<jr Jr. 






MM* | 




Or caci t ceftf cnct to *fl object 




ListPnpaitiai | 












Capvnim C 3MJ9 bv Dual' Coemufl ; lain. , ^ .udi! .u Kjzliu KticrwJ 
Sr-urd M\ : l<m K Fad Nn-Ttsh fXmjur ''Ml 




, Done 



The Evaluator Jr. has 26 variables (lowercase a through z) predefined for you. Therefore, you can assign 
values to variables, test comparison operators, and even do math here. Using the age variable examples 

continued 



113 



Part II: JavaScript Tutorial 



continued 

from earlier in this chapter, type each of the following statements in the upper text box, and observe 
how each expression evaluates in the Results field. Be sure to observe case sensitivity in your entries. 
The trailing semicolons are optional in The Evaluator. 

a = 45; 
a ; 

b = a - 15; 
b; 

a - b; 

a > b; 

To start over, click the Reload/Refresh button. 



The document . wri te ( ) method (remember, JavaScript uses the term method to mean command) 
requires a parameter in the parentheses: the text string to be displayed on the web page. The parame- 
ter here consists of one expression that joins three distinct strings: 

" of " 

navi gator . appName 

Tl IT 

The plus symbol is one of JavaScript's ways of joining strings. Before JavaScript can display this line, it 
must perform some quick evaluations. The first evaluation is the value of the navi gator . appName 
property. This property evaluates to a string of the name of your browser. With that expression safely 
evaluated to a string, JavaScript can finish the job of joining the three strings in the final evaluation. 
The evaluated string expression is what ultimately appears on the web page. 



Expressions and variables 

As one more demonstration of the flexibility that expression evaluation offers, this section shows you 
a slightly different route to the document, w r i t e ( ) statement. Rather than join those strings as the 
direct parameter to the document .wri te( ) method, you can gather the strings in a variable and 
then apply the variable to the document . wri te ( ) method. Here's how that sequence looks, as you 
simultaneously declare a new variable and assign it a value: 

var textToWrite = " of " + navi gator . appName + "."; 
document . wri te ( textToWri te ) ; 

This method works because the variable, textToWri te, evaluates to the combined string. The 
document, wri te ( ) method accepts that string value and does its display job. As you read a script 
or try to work through a bug, pay special attention to how each expression (variable, statement, 
object property) evaluates. As you learn JavaScript (or any language), you will end up scratching your 
head from time to time because you haven't stopped to examine how expressions evaluate when a 
particular kind of value is required in a script. 



114 



Chapter 8: Programming Fundamentals, Part I 



Data Type Conversions 

We mentioned earlier that the type of data in an expression can trip up some script operations if the 
expected components of the operation are not of the right type. JavaScript tries its best to perform 
internal conversions to head off such problems, but JavaScript cannot read your mind. If your inten- 
tions differ from the way JavaScript treats the values, you won't get the results you expect. 

A case in point is adding numbers that may be in the form of text strings. In a simple arithmetic 
statement that adds two numbers, you get the expected result: 

3+3 // result = 6 

But if one of those numbers is a string, JavaScript leans toward converting the other value to a 
string — thus turning the plus sign's action from arithmetic addition to joining strings. Therefore, in 
the statement 

3 + "3" // result = "33" 

the stringness of the second value prevails over the entire operation. The first value is automatically 
converted to a string, and the result joins the two strings. Try this yourself in The Evaluator Jr. 

If you take this progression one step further, look what happens when another number is added to 
the statement: 

3 + 3 + "3" // result = "63" 

This might seem totally illogical, but there is logic behind this result. The expression is evaluated from 
left to right. The first plus operation works on two numbers, yielding a value of 6. But as the 6 is 
about to be added to the 3, JavaScript lets the stringness of the 3 rule. The 6 is converted to a string, 
and two string values are joined to yield 63. 

Most of your concern about data types will focus on performing math operations like the ones here. 
However, some object methods also require one or more parameters of particular data types. Although 
JavaScript provides numerous ways to convert data from one type to another, it is appropriate at this 
stage of the tutorial to introduce you to the two most common data conversions: string to number and 
number to string. 

Converting strings to numbers 

As you saw in the preceding section, if a numeric value is stored as a string — as it is when entered 
into a form text field — your scripts may have difficulty applying that value to a math operation. The 
JavaScript language provides two built-in functions to convert string representations of numbers to 
true numbers: p a r s e I n t ( ) and parseFloatO. 

There is a difference between integers and floating-point numbers in JavaScript. Integers are always 
whole numbers, with no decimal point or numbers to the right of a decimal. Floating-point numbers, 
on the other hand, have fractional values to the right of the decimal. By and large, JavaScript math 
operations don't differentiate between integers and floating-point numbers: A number is a number. 
The only time you need to be cognizant of the difference is when a method parameter requires an 
integer because it can't handle fractional values. For example, parameters to the scrol 1 ( ) method of 
a window require integer values of the numbers of pixels vertically and horizontally that you want to 
scroll the window. That's because you can't scroll a window a fraction of a pixel onscreen. 



115 



Part II: JavaScript Tutorial 



To use either of these conversion functions, insert the string value you wish to convert as a parameter 
to the function. For example, look at the results of two different string values when passed through 
the p a r s e I n t ( ) function: 

parselnt( "42" ) // resul t = 42 

parselnt("42.33") // result = 42 

Even though the second expression passes the string version of a floating-point number to the func- 
tion, the value returned by the function is an integer. No rounding of the value occurs here (although 
other math functions can help with that if necessary). The decimal and everything to its right are 
simply stripped off. 

The parseFloat() function returns an integer if it can; otherwise, it returns a floating-point num- 
ber, as follows: 

parseFl oat( "42" ) // result = 42 

parseFloat("42.33") // result = 42.33 

Because these two conversion functions evaluate to their results, you simply insert the entire function 
wherever you need a string value converted to a number. Therefore, modifying an earlier example in 
which one of three values was a string, the complete expression can evaluate to the desired result: 

3 + 3 + parselnt( "3" ) // result = 9 

Converting numbers to strings 

You'll have less need for converting a number to its string equivalent than the other way around. As 
you saw in the previous section, JavaScript gravitates toward strings when faced with an expression 
containing mixed data types. Even so, it is good practice to perform data type conversions explicitly in 
your code to prevent any potential ambiguity. The simplest way to convert a number to a string is to 
take advantage of JavaScript's string tendencies in addition operations. By adding an empty string to a 
number, you convert the number to its string equivalent: 

("" + 2500) // result = "2500" 

("" + 2500). length // result = 4 

In the second example, you can see the power of expression evaluation at work. The parentheses force 
the conversion of the number to a string. A string is a JavaScript object that has properties associated 
with it. One of those properties is the 1 ength property, which evaluates to the number of charac- 
ters in the string. Therefore, the length of the string "2500" is 4. Note that the 1 ength value is a 
number, not a string. 

Operators 

You will use lots of operators in expressions. Earlier, you used the equal sign (=) as an assignment 
operator to assign a value to a variable. In the preceding examples with strings, you used the plus 
symbol (+) to join two strings. An operator generally performs some kind of calculation (operation) 
or comparison with two values (the value on each side of an operator is called an operand) to reach 
a third value. This lesson briefly describes two categories of operators: arithmetic and comparison. 
Chapter 22, "JavaScript Operators," covers many more operators, but after you understand the basics 
here, the others are easier to grasp. 



116 



Chapter 8: Programming Fundamentals, Part I 



Arithmetic operators 

It may seem odd to talk about text strings in the context of arithmetic operators, but you have already 
seen the special case of the plus (+) operator when one or more of the operands is a string. The plus 
operator instructs JavaScript to concatenate (pronounced "kon-KAT-en-eight"), or join, two strings 
together precisely where you place the operator. The string concatenation operator doesn't know about 
words and spaces, so the programmer must make sure that any two strings to be joined have the 
proper word spacing as part of the strings, even if that means adding a space: 

f i rstName = " John " ; 
1 astName = " Doe" ; 

fullName = firstName + " " + lastName; 

JavaScript uses the same plus operator for arithmetic addition. When both operands are numbers, 
JavaScript knows to treat the expression as an arithmetic addition rather than a string concatenation. 
The standard math operators for addition, subtraction, multiplication, and division (+, -, *, /) are 
built into JavaScript. 

Comparison operators 

Another category of operator helps you compare values in scripts — whether two values are the 
same, for example. These kinds of comparisons return a value of the Boolean type: true or f al se. 
Table 8-2 lists the comparison operators. The operator that tests whether two items are equal consists 
of a pair of equal signs to distinguish it from the single-equal-sign assignment operator. 



TABLE 8-2 



JavaScript Comparison Operators 


Symbol 


Description 


Equals 


! = Does not equal 


> 


Is greater than 


>= 


Is greater than or equal to 


< 


Is less than 


< = 


Is less than or equal to 



Comparison operators come into greatest play in the construction of scripts that make decisions as 
they run. A cook does this in the kitchen all the time: If the sauce is too watery, add a bit of flour. 
You see comparison operators in action in Chapter 22. 



117 



Part II: JavaScript Tutorial 



Exercises 



1 . Which of the following are valid variable declarations or initializations? Explain why each one 
is or is not valid. If an item is not valid, how do you fix it so that it is? 

a. my_name = "Ci nd" ; 

b. var how many = 25; 

c. var zipCode = document . getEl ementById( "zi p" ). val ue 

d. var laddress = document .(" addressl "). val ue ; 

2. Assume that the following statements operate rapidly in sequence, where each statement relies 
on the result of the one before it. For each of the statements in the sequence, write down how 
the s ome V a 1 expression evaluates after the statement executes in JavaScript. 

var someVal = 2; 
someVal = someVal + 2; 
someVal = someVal * 10; 
someVal = someVal + "20"; 
someVal = "Robert"; 

3. Name the two JavaScript functions that convert strings to numbers. How do you give the 
function a string value to convert to a number? 

4. Type and load the HTML page and script shown in Listing 8-1. Enter a three-digit number in 
the top two fields, and click the Add button. Examine the code, and explain what is wrong with 
the script. How do you fix the script so that the proper sum is displayed in the output field? 



LISTING 8-1 



What's Wrong with This Script? 

HTML: jsb-08-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<t i tl e>Ma ki ng Sums</title> 

<script type=" text/javascript" src="../jsb-global .js"X/script> 
<script type=" text/javascript" src="jsb-08-01.js"X/script> 
</head> 
<body> 

<hl>Making Sums</hl> 
<form acti on = "addi t . php"> 

<p><input type="text" id="inputA" name=" i nputA" val ue="0"X/p> 
<p><input type="text" id="inputB" name=" i nputB " val ue="0"X/p> 
<p><input type="button" id="add" name="add" val ue="Add"X/p> 
<p><input type="text" id="output" name="output"X/p> 
</f orm> 
</body> 
</html > 



118 



Chapter 8: Programming Fundamentals, Part I 



JavaScript: jsb-08-01.js 

// initialize when the page has loaded 
add Event (wi ndow , 'load', initialize); 

function i n i t i a 1 i z e ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . get El ementBy Id ) 

{ 

// point to critical elements 

var olnputA = document . get El ementBy Id (' i nputA ') ; 
var olnputB = document . getEl ementById( ' i nputB ') ; 
var oButton = document . get El ementBy Id (' add ') ; 
var oOutput = document . getEl ementBy Id( ' output ') ; 

// if they all exi st . . . 

if (olnputA && olnputB && oButton && oOutput) 
{ 

// apply behaviors 
addEvent(oButton , 'click', addlt); 

) 




// add two input numbers & display result 
function addlt() 

{ 

var valuel = document . get El ementBy I d (" i nputA" ). val ue ; 
var value2 = document . get El ementBy I d (" i nputB "). val ue ; 

document . getEl ementByldC "output" ). val ue = valuel + value2; 

) 



5. What does the term concatenate mean in the context of JavaScript programming? 



119 



CHAPTER 



Programming 
Fundamentals, Part II 



Your tour of programming fundamentals continues in this chapter with 
subjects that have more intriguing possibilities. For example, we show you 
how programs make decisions and why a program must sometimes repeat 
statements over and over. Before you're finished here, you also will learn how 
to use one of the most powerful information holders in the JavaScript language: 
the array. 



Decisions and Loops 



Every waking hour of every day, you make decisions of some kind; most of the 
time, you probably don't even realize it. Don't think so? Well, look at the num- 
ber of decisions you make at the grocery store, from the moment you enter the 
store to the moment you clear the checkout aisle. 

No sooner do you enter the store than you are faced with a decision. Based on 
the number and size of items you intend to buy, do you pick up a hand-carried 
basket or attempt to extricate a shopping cart from the metallic conga line near 
the front of the store? That key decision may have impact later, when you see a 
special offer on an item that is too heavy to put in the handbasket. 

Next, you head for the food aisles. Before entering an aisle, you compare the 
range of goods stocked in that aisle with items on your shopping list. If an item 
you need is likely to be found in this aisle, you turn into the aisle and start 
looking for the item; otherwise, you skip the aisle and move to the head of the 
next aisle. 

Later, you reach the produce section in search of a juicy tomato. Standing in 
front of the bin of tomatoes, you begin inspecting them one by one — picking 
one up, feeling its firmness, checking the color, looking for blemishes or signs 
of pests. You discard one, pick up another, and continue this process until one 
matches the criteria you set in your mind for an acceptable morsel. Your last stop 
in the store is the checkout aisle. "Paper or plastic?" the clerk asks. One more 
decision to make. What you choose affects how you get the groceries from the 
car to the kitchen, as well as your recycling habits. 



IN THIS CHAPTER 



How control structures make 
decisions 

How to define functions 

Where to initialize variables 
efficiently 

What those darned curly 
braces are all about 

The basics of data arrays 



121 



Part II: JavaScript Tutorial 



During your trip to the store, you go through the same kinds of decisions and repetitions that your 
JavaScript programs encounter. If you understand these frameworks in real life, you can look into the 
JavaScript equivalents and the syntax required to make them work. 

Control Structures 

In the vernacular of programming, the kinds of statements that make decisions and loop around to 
repeat themselves are called control structures. A control structure directs the execution flow through 
a sequence of script statements based on simple decisions and other factors. 

An important part of a control structure is the condition. Just as you may travel different routes to work 
depending on certain conditions (for example, nice weather, nighttime, whether you're attending a 
soccer game), so, too, does a program sometimes have to branch to an execution route if a certain 
condition exists. Each condition is an expression that evaluates to true or false — one of those 
Boolean data types mentioned in Chapter 8. The kinds of expressions commonly used for conditions 
are expressions that include a comparison operator. You do the same in real life: If it is true that the 
outdoor temperature is less than freezing, you put on a coat before going outside. In programming, 
the comparisons are strictly comparisons of numeric values and character strings. 

JavaScript provides several kinds of control structures for different programming situations. Three of 
the most common control structures you'll use are i f constructions, if. . .else constructions, and 
for loops. 

Chapter 21 covers in great detail other common control structures you should know. For this tutorial, 
however, you need to learn about the three common ones just mentioned. 

if constructions 

The simplest program decision is to follow a special branch or path of the program if a certain con- 
dition is true. Formal syntax for this construction follows. Items in italics get replaced in a real script 
with expressions and statements that fit the situation. 

if {condition) 

{ 

statement[s] if true 

} 

Don't worry about the curly braces yet. Instead, get a feel for the basic structure. The keyword, if, is 
a must. Between the parentheses goes an expression that evaluates to a Boolean (true/false) value. This 
is the condition being tested as the program runs past this point. If the condition evaluates to true, 
one or more statements inside the curly braces execute before the program continues with the next 
statement after the closing brace. If the condition evaluates to f al se, the statements inside the curly 
braces are ignored, and processing continues with the next statement after the closing brace. 

The following example assumes that a variable, myAge, has had its value set earlier in the script 
(exactly how is not important for this example). The conditional expression compares the value 
myAge against a numeric value of 13: 

if (myAge < 13) 

{ 

alert("You are rot yet a teenager."); 

1 



122 



Chapter 9: Programming Fundamentals, Part II 



In this example, the data type of the value inside my Age must be a number so that the proper 
comparison (via the <, or less than, comparison operator) does the right thing. For all instances of 
my Age less than 13, the nested statement inside the curly braces runs and displays the alert to the 
user. After the user closes the alert dialog box, the script continues with whatever statement follows 
the entire i f construction. 



if . . . else constructions 

Not all program decisions are as simple as the one shown for the i f construction. Rather than speci- 
fying one detour for a given condition, you might want the program to follow either of two branches 
depending on that condition. It is a fine but important distinction. In the plain i f construction, no 
special processing is performed when the condition evaluates to false. But if processing must follow 
one of two special paths, you need the if. . .else construction. The formal syntax definition for an 
if. . .else construction is as follows: 

if (condition) 
{ 

statement[s] if true 

} 

else 
{ 

statement[s] if false 

} 

Everything you know about the condition for an i f construction applies here. The only difference is 
the else keyword, which provides an alternative path for execution to follow if the condition evalu- 
ates to f al se. 

As an example, the following if. . .else construction determines how many days are in February 
for a given year. To simplify the demo, the condition simply tests whether the year divides equally by 
4. (True testing for this value includes special treatment of end-of-century dates, but we're ignoring 
that for now.) The % operator symbol is called the modulus operator (covered in more detail in Chapter 
22). The result of an operation with this operator yields the remainder of division of the two values. If 
the remainder is zero, the first value divides evenly by the second. 

var febDays; 

var theYear = 2010; 

if (theYear % 4 == 0) 

{ 

febDays = 29; 

} 

else 
{ 

febDays = 28; 

} 

The important point to see from this example is that by the end of the if. . .else construction, the 
febDays variable is set to either 28 or 29. No other value is possible. For years evenly divisible by 4, 
the first nested statement runs. For all other cases, the second statement runs. Then processing picks 
up with the next statement after the i f . . . e 1 s e construction. 



123 



Part II: JavaScript Tutorial 



Repeat Loops 

Repeat loops in real life generally mean the repetition of a series of steps until some condition is 
met, thus enabling you to break out of that loop. Such was the case earlier in this chapter, when you 
looked through a bushel of tomatoes for the one that came closest to your ideal tomato. The same can 
be said for driving around the block in a crowded neighborhood until a parking space opens up. 

A repeat loop lets a script cycle through a sequence of statements until some condition is met. For 
example, a JavaScript data validation routine might inspect every character that you enter in a form 
text field to make sure that each one is a number. Or, if you have a collection of data stored in a list, 
the loop can check whether an entered value is in that list. When that condition is met, the script can 
break out of the loop and continue with the next statement after the loop construction. 

The most common repeat loop construction used in JavaScript is called the for loop. It gets its name 
from the keyword that begins the construction. A for loop is a powerful device because you can set 
it up to keep track of the number of times the loop repeats itself. The formal syntax of the for loop 
is as follows: 

for {[initial expression]; [condition]; [update expression]) 

{ 

statement[s] inside loop 

} 

The square brackets mean that the item is optional. However, until you get to know the for loop 
better, we recommend designing your loops to use all three items inside the parentheses. The initial 
expression portion usually sets the starting value of a counter variable. The condition — the same kind 
of condition you saw for i f constructions — defines the condition that forces the loop to stop going 
around and around. Finally, the update expression is a statement that executes each time all the state- 
ments nested inside the construction complete running. 

A common implementation initializes a counting variable, i ; increments the value of i by 1 each time 
through the loop; and repeats the loop until the value of i exceeds some maximum value, as in the 
following: 

for (var i = startValue; i <= maxValue; i++) 

{ 

statement[s] inside loop 

} 

Placeholders startVal ue and maxVal ue represent any numeric values, including explicit numbers 
or variables holding numbers. In the update expression is an operator we have not presented yet. The 
++ operator adds 1 to the value of i each time the update expression runs at the end of the loop. 
IfstartValueisl, the value of i is 1 the first time through the loop, 2 the second time through, 
and so on. Therefore, if maxVal ue is 10, the loop repeats itself 10 times (in other words, as long as 
i is less than or equal to 10). Generally speaking, the statements inside the loop use the value of the 
counting variable in their execution. Later in this lesson, we show how the variable can play a key role 
in the statements inside a loop. At the same time, you will see how to break out of a loop prematurely 
and why you may need to do this in a script. 

Functions 

In Chapter 7, you saw a preview of the JavaScript function. A junction is a definition of a set of 
deferred actions. Functions are invoked by event handlers or by statements elsewhere in the script. 



124 



Chapter 9: Programming Fundamentals, Part II 



Whenever possible, good functions are designed for reuse in other documents. They can become 
building blocks you use over and over again. 

If you have programmed before, you can see parallels between JavaScript functions and other lan- 
guages' subroutines. But unlike some languages that distinguish between procedures (which carry out 
actions) and functions (which carry out actions and return values), only one classification of routine 
exists for JavaScript. A function is capable of returning a value to the statement that invoked it, but 
this is not a requirement. When a function does return a value, the calling statement treats the func- 
tion call like any expression — plugging in the returned value right where the function call is made. 
We will show some examples in a moment. 

Formal syntax for a function is as follows: 

function functi onNarne ( [parameterl] . . .[ .parameterN] ) 
{ 

statement[s] 

} 

Names you assign to functions have the same restrictions as names you assign to HTML elements and 
variables. You should devise a name that succinctly describes what the function does. We tend to use 
multiword names with the CamelCase or interCap (internally capitalized) format that start with a verb 
because functions are action items, even if they do nothing more than get or set a value. 

Another practice to keep in mind as you start to create functions is to keep the focus of each func- 
tion as narrow as possible. It is possible to generate functions that are literally hundreds of lines long. 
Such functions are usually difficult to maintain and debug. Chances are that you can divide the long 
function into smaller, more tightly focused segments. 



Function parameters 

In Chapter 4, you saw how an event handler invokes a function by calling the function by name. A 
typical call to a function, including one that comes from another JavaScript statement, works the same 
way: A set of parentheses follows the function name. 

You also can define functions so that they receive parameter values from the calling statement. Listing 
9-1 shows a simple script in which a statement passes text data to a function at the same time that it 
calls the function. 



LISTING 9-1 



Calling a Function from an Event Handler 

HTML: jsb-09-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf 

<t i tl e>Pass i ng a Parameter to a Functi on</ti tl e> 
<script type=" text/javascript" src="jsb-09-01.js"X/script> 
</head> 



-8"> 



continued 



125 



Part II: JavaScript Tutorial 



LISTING 9-1 



(continued) 



<body> 

<hl>Passing a Parameter to a Functi on</hl> 
</body> 
</html > 

JavaScript: jsb-09-01.js 

// display a personalized greeting 
function greet ing(sNa me) 

{ 

alert( "Hel 1 o, " + sName + " ! " ) ; 



greeti ng ( "Ch ri s " ) ; 



Parameters (also known as arguments) provide a mechanism for handing off a value from one state- 
ment to another by way of a function call. If no parameters occur in the function definition, both 
the function definition and the call to the function have only empty sets of parentheses (as shown 
in Chapter 4, Listing 4-2). 

When a function receives parameters, it assigns the incoming values to the variable names specified in 
the function definition's parentheses. Consider the following script segment: 

function sayHel 1 oFi rst ( a , b, c) 

{ 

a 1 ert ( " Say hello, " + a ) ; 

} 

sayHel 1 oFi rst( "Graci e" , "George", "Harry"); 
sayHel 1 oFi rst( " Larry" , "Moe", "Curly"); 

After the function is defined in the script, the next statement calls that very function, passing three 
strings as parameters. The function definition automatically assigns the strings to variables a, b, and 
c. Therefore, before the a 1 e rt ( ) statement inside the function ever runs, a evaluates to " Gr a ci e " , 
b evaluates to "George", and c evaluates to "Harry". In the al ert( ) statement, only the a value 
is used, and the alert reads 

Say hello, Gracie 

When the user closes the first alert, the next call to the function occurs. This time through, different 
values are passed to the function and assigned to a , b , and c . The alert dialog box reads 

Say hello, Larry 

Unlike other variables that you define in your script, function parameters do not use the va r keyword 
to initialize them. They are automatically initialized whenever the function is called. 



126 



Chapter 9: Programming Fundamentals, Part II 



Variable scope 

Speaking of variables, it's time to distinguish between variables that are defined outside and those that 
are defined inside functions. Variables defined outside of functions are called global variables; those 
defined inside functions with the v a r keyword are called local variables. 

A global variable has a slightly different connotation in JavaScript than it has in most other languages. 
For a JavaScript script, the globe of a global variable is the current document loaded in a browser 
window or frame. Therefore, when you initialize a variable as a global variable, it means that all script 
statements in the page (including those inside functions) have direct access to that variable's value via 
the variable's name. Statements can retrieve and modify global variables from anywhere in the script. 
In programming terminology, this kind of variable is said to have global scope because every statement 
on the page can see it. 

It is important to remember that the instant a page unloads itself, all global variables defined in that 
page disappear from memory forever. If you need a value to persist from one page to another, you 
must use other techniques to store that value (for example, as a global variable in a framesetting doc- 
ument, as described in Chapter 27, "Window and Frame Objects," or in a cookie, as described in 
Chapter 29, "The Document and Body Objects." Although the var keyword is usually optional for 
initializing global variables, we strongly recommend that you use it for all variable initializations to 
guard against future changes to the JavaScript language. 

In contrast to the global variable, a local variable is defined inside a function. You already saw how 
parameter variables are defined inside functions (without var keyword initializations). But you can 
also define other variables with the var keyword (absolutely required for local variables; otherwise, 
they become recognized as global variables). The scope of a local variable is only within the statements 
of the function. No other functions or statements outside functions have access to a local variable. 

Local scope allows for the reuse of variable names within a document. For most variables, we strongly 
discourage this practice because it leads to confusion and bugs that are difficult to track down. At 
the same time, it is convenient to reuse certain kinds of variable names, such as for loop counters. 
These are safe because they are always reinitialized with a starting value whenever a for loop starts. 
In order to nest one for loop inside another, you need to specify a different loop-counting variable in 
the nested loop. 

To demonstrate the structure and behavior of global and local variables — and show you why it can 
get confusing to reuse most variable names inside a script — Listing 9-2 defines two global variables 
and a local one. For the purposes of this illustration, we intentionally use bad form by initializing a 
local variable that has the same name as a global variable. 



LISTING 9-2 



Global and Local Variable Scope Demonstration 

HTML: jsb-09-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<titl e>Gl obal and Local Variable Scope</ti tl e> 

continued 



127 



Part II: JavaScript Tutorial 



LISTING 9-2 



(continued) 



<script type=" text/javascript" src="jsb-09-02.js"X/script> 
</head> 
<body> 

<hl>Global and Local Variable Scope</hl> 
</body> 
</html > 

JavaScript: jsb-09-02.js 

var Boy = "Charlie Brown"; // global 
var Dog = "Snoopy"; // global 

// using improper design to demonstrate a point 
f uncti on demo( ) 

{ 

// local variable with the same name as a global 
var Dog = "Gromi t" ; 

alert(Dog + " does not belong to " + Boy + "."); 



// use global variables 

alert(Dog + " belongs to " + Boy + "."); 

// use global & local variables 
demo ( ) ; 



When the page loads, the script initializes the two global variables (Boy and Dog) and defines the 
demo( ) function in memory. Inside the function, a local variable is initialized with the same name as 
one of the global variables: Dog. In JavaScript, such a local initialization overrides the global variable 
for all statements inside the function. (But note that if we had omitted the var keyword from the local 
initialization, the variable Dog inside the function would have referred to the global variable — i.e., 
"Gromi t".) 

The script displays two al ert dialogs. The first to appear concatenates the two global variables to 
display: 

Snoopy belongs to Charlie Brown. 

The second dialog, invoked by calling the function demo ( ) in the last line of the script, occurs inside 
the demo( ) function and therefore uses the local variable Dog instead of the global one: 

Gromit does not belong to Charlie Brown. 



Curly Braces 

Despite the fact that you probably rarely — if ever — use curly braces ( { ) ) in your writing, there 
is no mystery to their usage in JavaScript (and many other languages). Curly braces enclose blocks of 



128 



Chapter 9: Programming Fundamentals, Part II 



statements that belong together. Although they do assist humans who are reading scripts in knowing 
what's going on, curly braces also help the browser know which statements belong together. You 
always must use curly braces in matched pairs. 

You use curly braces most commonly in function definitions and control structures. In the function 
definition in Listing 9-2, curly braces enclose three statements (including the comment line) that make 
up the function definition. The closing brace lets the browser know that whatever statement comes 
next is a statement outside the function definition. 

Physical placement of curly braces is not critical. (Neither is the indentation style you see in the code 
we provide.) The following function definitions are treated identically by scriptable browsers: 

function sayHiToFi rst(a , b, c) 
{ 

alert( "Say hel 1 o , " + a) ; 

} 

function sayHi ToFi rst ( a , b, c) { 
a 1 ert ( "Say hello, " + a) ; 



function sayHi ToFi rst ( a , b, c) {alert("Say hello, " + a);) 

Throughout this book, we use the style shown in the first example because we find that it makes 
lengthy and complex scripts easier to read — especially scripts that have many levels of nested control 
structures. However, this aspect of scripting style is highly personal and varies from one programmer 
to another — even among the co-authors of this book! 



Arrays 

The JavaScript array is one of the most useful data constructions you have available to you. You can 
visualize the structure of a basic array as though it were a single-column spreadsheet. Each row of 
the column holds a distinct piece of data, and each row is numbered. Numbers assigned to rows are 
in strict numerical sequence, starting with zero as the first row. (Computers tend to start counting 
with zero.) This row number is called an index. To access an item in an array, you need to know the 
name of the array and the index for the row. Because index values start with zero, the total number of 
items of the array (as determined by the array's length property) is always one more than the highest 
index value of the array. More advanced array concepts enable you to create the equivalent of an array 
with multiple columns (described in Chapter 18). For this tutorial, we stay with the single-column 
basic array. 

Data elements inside JavaScript arrays can be any data type, including objects. And unlike a lot of 
other programming languages, JavaScript allows different rows of the same array to contain different 
data types. 

Creating an array 

An array is stored in a variable, so when you create an array, you assign the new array object to the 
variable. (Arrays are objects that belong to the core JavaScript language rather than to the document 
object model [DOM].) A special keyword — new — preceding a call to the JavaScript function that 
generates arrays creates space in memory for the array. An optional parameter to the Array ( ) func- 
tion enables you to specify at the time of creation how many elements (rows) of data eventually will 
occupy the array. JavaScript is very forgiving about this because you can change the size of an array 



129 



Part II: JavaScript Tutorial 



at any time. Therefore, if you omit a parameter when generating a new array, your script incurs no 
penalty. 

To demonstrate the array creation process, we create an array that holds the names of the 50 U.S. 
states plus the District of Columbia (a total of 51). The first task is to create that array and assign it to 
a variable of any name that helps us remember what this collection of data is about: 

var USStates = new Array(51); 

At this point, the USStates array is sitting in memory like a 51-row table with no data in it. To fill 
the rows, we must assign data to each row. Addressing each row of an array requires a special way of 
indicating the index value of the row: square brackets after the name of the array. The first row of the 
USStates array is addressed as: 

USStates[0] 

To assign the string name of the first state of the alphabet to that row, use a simple assignment 
operator: 

USStates [0] = "Al abama " ; 

To fill in the rows, include a statement for each row: 

USStates [0] = "Al abama " ; 

USStates[l] = "Alaska"; 

USStates[2] = "Arizona"; 

USStates[3] = "Arkansas"; 

USStates[50] = "Wyoming"; 

(Note that the 51st array element has an index of 50 because we're starting with 0, not 1.) 

Therefore, if you want to include a table of information from which a script can look up informa- 
tion without accessing the server, you include the data in the script in the form of an array creation 
sequence. When the script loads into the browser and the statements run, the data collection array is 
built and ready to go. Despite what appears to be the potential for a lot of statements in a document 
for such a data collection, the amount of data that must download for typical array collections is small 
enough not to affect page loading severely — even for dial-up users. In Chapter 18, you also see some 
syntax shortcuts for creating arrays that reduce source code character counts. 



Accessing array data 

The array index is the key to accessing an array element. The name of the array and an index in 
square brackets evaluates to the content of that array location. For example, after the USStates array 
is built, a script can display an alert with Alaska's name in it with the following statement: 

alert("The largest state is " + USStatesfl] + "."); 

Just as you can retrieve data from an indexed array element, you can change the element by reassign- 
ing a new value to any indexed element in the array. 



130 



Chapter 9: Programming Fundamentals, Part II 



Parallel arrays 

Now we show you why the numeric index methodology works well in JavaScript. To help with the 
demonstration, we generate another array that is parallel with the USStates array. This new array 
is also 51 elements long, and it contains the year in which the state in the corresponding row of 
USStates entered the Union. That array construction looks like the following: 

var stateEntered = new Array(51); 

stateEntered [0] = 1819; 

stateEntered [1] = 1959; 

stateEntered [2] = 1912; 

stateEntered [3] = 1836; 

stateEntered [50] = 1890; 

In the browser's memory, then, are two data tables that you can visualize as looking like the model in 
Figure 9-1. We can build more arrays that are parallel to these for items such as the postal abbrevia- 
tion and capital city. The important point is that the zeroth element in each of these tables applies to 
Alabama, the first state in the USStates array. 



FIGURE 9-1 



Visualization of two related parallel data tables. 



USStates 




stateEntered 


"Alabama" 


[0] 


1819 


"Alaska" 


[1] 


1959 


"Arizona" 


[2] 


1912 


"Arkansas" 


[3] 


1836 








"Wyoming" 


[50] 


1890 



If a web page included these data tables and a way for a user to look up the entry date for a given 
state, the page would need a way to look through all the USStates entries to find the index value of 
the one that matches the user's entry. Then that index value could be applied to the stateEntered 
array to find the matching year. 

For this demo, the page includes a text entry field in which the user types the name of the state to 
look up. This methodology is fraught with peril unless the script performs some error checking in case 
the user makes a mistake. Let's not assume that the user always types a valid state name; instead, let's 
gracefully handle the circumstance in which they don't. (Don't ever assume that user input is valid in 
your web site's pages.) An event handler from either the text field or a clickable button calls a function 
that looks up the state name, fetches the corresponding entry year, and displays an alert message with 
the information. The function is as follows: 

function getStateDate ( ) 
{ 

var sel ectedState = document . getEl ementBy I d (" entry "). val ue ; 
for (var i = 0; i < USStates . 1 ength ; i++) 

{ 



131 



Part II: JavaScript Tutorial 



if (USStatesfi] == sel ectedState ) 

{ 

break ; 

) 

) 

if (i < USStates . 1 ength) 
{ 

al ert( sel ectedState + " entered the Union in " + stateEn- 
tered[i ] + " . " ) ; 
) 

else 
{ 

al ert( "Sorry , '" + sel ectedState + "' isn't a US state."); 

} 

} 

In the first statement of the function, we grab the value of the text box and assign the value to a vari- 
able, sel ectedState. This is mostly for convenience, so that we can use this shorter variable name 
later in the script. In fact, the usage of that value is inside a for loop, so the script is marginally more 
efficient because the browser doesn't have to evaluate that long reference to the text field each time 
through the loop. 

The key to this function is in the for loop. Here is where we combine the natural behavior of incre- 
menting a loop counter with the index values assigned to the two arrays. Specifications for the loop 
indicate that the counter variable, i , is initialized with a value of zero. The loop is directed to con- 
tinue as long as the value of i is less than the length of the USStates array. Remember that the 
length of an array is always one more than the index value of the last item. Therefore, the last time 
the loop runs is when i is 50, which is both less than the length of 51 and equal to the index value 
of the last element. Each time after the loop runs, the counter increments by 1 (i ++). 

Nested inside the for loop is an i f construction. The condition tests the value of an element of the 
array against the value typed by the user. Each time through the loop, the condition tests a differ- 
ent row of the array, starting with row zero. In other words, this i f construction can be performed 
dozens of times before a match is found, but each time, the value of i is 1 larger than in the previ- 
ous try. 

The equality comparison operator (==) is fairly strict when it comes to comparing string values. Such 
comparisons respect the case of each letter. In our example, the user must type the state name exactly 
as it is stored in the USStates array for the match to be found. In Chapter 12, you learn about some 
helper methods that eliminate case and sensitivity in string comparisons. 

When a match is found, the statement nested inside the i f construction runs. The break statement 
is designed to help control structures bail out if the program needs it. For this application, it is imper- 
ative that the for loop stop running when a match for the state name is found. When the for loop 
breaks, the value of the i counter is fixed at the row of the USStates array containing the entered 
state. We need that index value to find the corresponding entry in the other array. Even though the 
counting variable, i , is initialized in the for loop, it is still alive and in the scope of the function for 
all statements after the initialization. That's why we can use it to extract the value of the row of the 
stateEntered array in the final statement that displays the results in an alert message. 

If the entered state name doesn't match any of the values in the USStates array, the counter variable 
i increments to the length of the array (51) and the for loop terminates, leaving i equal to 51. From 



132 



Chapter 9: Programming Fundamentals, Part II 



that we can easily tell whether we successfully found a state name match and display an error message 
if no match was found. 

This application of a for loop and array indexes is a common one in JavaScript. Study the code care- 
fully, and be sure you understand how it works. This way of cycling through arrays plays a role not 
only in the kinds of arrays you create in your code, but also in the arrays that browsers generate for 
the DOM. 

Document objects in arrays 

If you look at the document object portions of the Quick Reference in Appendix A, you can see 
that the properties of some objects are listed with square brackets after them. These are indeed the 
same kind of square brackets you just saw for array indexes. That's because when a document loads, 
the browser creates arrays of like objects in the document. For example, if your page includes two 
<f orm> tag sets, two forms appear in the document. The browser maintains an array of form objects 
for that document. References to those forms are 

document . forms [0] 
document . forms [ 1 ] 

You can also capture this array using the DOM method getEl ementsByTagName ( ): 

var aForms = document . getEl ementsByTagName( ' form' ) ; 
and then refer to the form array items with: 

aForms[0] 
aFormsfl] 

Index values for objects are assigned according to the loading order of the objects. In the case of form 
objects, the order is dictated by the order of the <f orm> tags in the document. This indexed array 
syntax is another way to reference forms in an object reference. You can still use a form's identifier (i d 
attribute) if you prefer — and we heartily recommend using object names wherever possible, because 
even if you change the physical order of the objects in your HTML, references that use names still 
work without modification. But if your page contains only one form, you can use the reference types 
interchangeably, as in the following examples of equivalent references to the length property of a 
form's el ements array (the el ements array contains all the form controls in the form): 

document. getEl ement By Id("entryForm").elements. length 
document . forms [0] . el ements . 1 ength 

document. getEl ement sByTagName( 'form' )[0] .el ements. length 

In examples throughout this book, you can see that we often use the array type of reference to simple 
forms in simple documents. But in our production pages, we almost always use named references. 

Exercises 



1 . With your newly acquired knowledge of functions, event handlers, and control structures, use 
the script fragments from this chapter to complete the page that has the lookup table for all the 
states and the years they entered into the union. If you do not have a reference book for the 
dates, use different year numbers, starting with 1800 for each entry. In the page, create a text 
entry field for the state and a button that triggers the lookup in the arrays. 



133 



Part II: JavaScript Tutorial 



2. Examine the following function definition. Can you spot any problems with the definition? If 
so, how can you fix the problems? 

function format(ohmage) 
{ 

var result; 

if ohmage >= le6 

{ 

ohmage = ohmage / le6; 
result = ohmage + " Mohms"; 



if (ohmage >= le3) 

ohmage = ohmage / le3; 

result = ohmage + " Kohms"; 
else 

result = ohmage + " ohms"; 

} 

al ert( resul t) ; 

3. Devise your own syntax for the scenario of looking for a ripe tomato at the grocery store, and 
write a f o r loop using that object and property syntax. 

4. Modify Listing 9-2 so that it does not reuse the Dog variable inside the function. 

5. Given the following table of data about several planets of our solar system, create a web page 
that enables users to enter a planet name and, at the click of a button, have the distance and 
diameter appear either in an alert box or (as extra credit) in separate fields of the page. 



Planet Distance from the Sun Diameter 



Mercury 


36 million miles 


3,100 miles 


Venus 


67 million miles 


7,700 miles 


Earth 


93 million miles 


7,920 miles 


Mars 


141 million miles 


4,200 miles 



134 



Window and 
Document Objects 




Now that you have exposure to programming fundamentals, it is easier 
to demonstrate how to script objects in documents. Starting with this 
lesson, the tutorial turns back to the Document Object Model (DOM), 
diving more deeply into the objects you will place in many of your documents. 



Top-Level Objects 



As a refresher, study the hierarchy of top-level objects in Figure 10-1. This 
chapter focuses on objects of this level that you'll frequently encounter in your 
scripting: wi ndow, 1 ocati on, navi gator, and document. The goal is not 
only to equip you with the basics so you can script simple tasks, but also to 
prepare you for the in-depth examinations of each object and its properties, 
methods, and event handlers, that you will find in Part IV, "Document Objects 
Reference." We introduce only the basic properties, methods, and events for 
objects in this tutorial. Examples in Part IV of the book assume that you know 
the programming fundamentals covered here in Part II. 



The window Object 



At the top of the object hierarchy is the wi ndow object. This object gains 
that exalted spot in the object food chain because it is the master container 
for all content you view in the web browser. As long as a browser window is 
open — even if no document is loaded in the window — the wi ndow object is 
defined in the current model in memory. 

In addition to the content part of the window where documents go, a window's 
sphere of influence includes the dimensions of the window and all the stuff that 
surrounds the content area. The area where scrollbars, toolbars, the status bar, 
and (non-Macintosh) menu bar live is known as a window's chrome. Not every 
browser has full scripted control over the chrome of the main browser window, 



IN THIS CHAPTER 



What the window object does 

How to access key window 
object properties and 
methods 

How to trigger script actions 
after a document loads 

The purposes of the location 
and navigator objects 

How the document object is 
created 

How to access key document 
object properties and 
methods 



135 



Part II: JavaScript Tutorial 



but you can easily script the creation of additional windows sized the way you want and with only the 
chrome elements you wish to display. 



FIGURE 10-1 



The top-level browser object model for all scriptable browsers. 





window 












I I 


I I 


navigator screen 


history location 












document 





Although the discussion of frames comes in Chapter 13, "Scripting Frames and Multiple Windows," 
we can now safely say that each frame is also considered a wi ndow object. If you think about it, 
that makes sense, because each frame can hold a different document. When a script runs in one of 
those documents, it regards the frame that holds the document as the wi ndow object in its view of 
the object hierarchy. 

As you will learn in this chapter, the wi ndow object is a convenient place for the DOM to attach 
methods that display modal dialog boxes and adjust the text that displays in the status bar at the bot- 
tom of the browser window. A wi ndow object method enables you to create a separate window that 
appears onscreen. When you look at all of the properties, methods, and events defined for the wi n- 
dow object (see Chapter 27, "Window and Frame Objects"), it should be clear why they are attached 
to window objects: Visualize their scope and the scope of a browser window. 

Note 

In the modern crop of browsers, the user is given the choice of opening web pages either in new tabs within 
one browser or in new browser windows, which are separate copies of the browser program on the desk- 
top. JavaScript does not exert any control whatsoever over this choice, which remains the user's prerogative. 
Browser windows and browser tabs are both identically wi ndow objects to JavaScript. Efforts to control fea- 
tures such as window size and the appearance of toolbars will either fail or will frustrate the user's attempts 
to make their browser conform to their own personal usability standards. In other words, if you don't want to 
irritate web site visitors, don't try to mess with their settings. Trust users to manage their browsers. Focus your 
creative energies on the content and style of the page, not the window chrome. ■ 

Accessing window properties and methods 

You can word script references to properties and methods of the wi ndow object in several ways, 
depending more on whim and style than on specific syntactical requirements. The most logical and 
common way to compose such references includes the wi ndow object in the reference: 

wi ndow . propertyName 

wi ndow . methodNamei [parameters]) 



136 



Chapter 10: Window and Document Objects 



A wi ndow object also has a synonym when the script doing the referencing points to the window that 
houses the document. The synonym is self. Then the reference syntax becomes 

self. propertyName 

self. methodNamei [parameters]) 

You can use these initial reference object names interchangeably, but we tend to reserve the use of 
self for more complex scripts that involve multiple frames and windows. The self moniker more 
clearly denotes the current window holding the script's document, and can make the script more 
readable — by us and by others. 

Back in Chapter 6, "Browser and Document Objects," we indicated that because the wi ndow object is 
always there when a script runs, you can omit it from references to any objects inside that window. 
Therefore, the following syntax models assume properties and methods of the current window: 

propertyName 
methodNamei [parameters]) 

In fact, as you will see in a few moments, some methods may be more understandable if you omit the 
wi ndow object reference. The methods run just fine either way. 

Creating a window 

A script does not create the main browser window. A user does that by virtue of launching the 
browser or by opening a URL or file from the browser's menus (if the window is not already open). 
But a script can generate a large number of subwindows when the main window is open (and that 
window contains a document whose script needs to open subwindows). 

The method that generates a new window is window.open( ). This method contains up to three 
parameters that define window characteristics: the URL of the document to load, its name for 
target attribute reference purposes in HTML tags, and physical appearance (size and chrome 
contingent). We don't go into the details of the parameters here (they're covered in great depth 
in Chapter 27), but we do want to expose you to an important concept involved with the 
wi ndow . open ( ) method. 

Consider the following statement, which opens a new window to a specific size and with an HTML 
document from the same server directory that holds the current page: 

var subWindow = wi ndow. open( "defi ne . html ", "def" , "hei ght=200 ,wi dth=300" ) ; 

The important thing to note about this statement is that it is an assignment statement. Some- 
thing gets assigned to that variable subWindow. What is it? It turns out that when the 
wi ndow . open ( ) method runs, it not only opens that new window according to specifications 
set as parameters, but also evaluates to a reference to that new window. In programming parlance, the 
method is said to return a value — in this case, a genuine object reference. The value returned by the 
method is assigned to the variable. 

Now your script can use that variable as a valid reference to the second window. If you need to 
access one of its properties or methods, you must use that reference as part of the complete reference. 
For example, to close the subwindow from a script in the main window, use this reference to the 
cl ose( ) method for that subwindow: 

subWi ndow . cl ose ( ) ; 



137 



Part II: JavaScript Tutorial 



If you issue window.closeO, self.close(),or just c 1 o s e ( ) in the main window's script, the 
method closes the main window (after confirming with the user), but not the subwindow. To address 
another window, then, you must include a reference to that window as part of the complete reference. 
This has an impact on your code because you probably want the variable holding the reference to the 
subwindow to be valid as long as the main document is loaded into the browser. For that to happen, 
the variable has to be initialized as a global variable, rather than inside a function (although you can 
set its value inside a function). That way, one function can open the window while another function 
closes it. 

Listing 10-1 is a page that has a button for opening a blank new window and a button for closing that 
window from the main window. To view this demonstration, shrink your main browser window to 
less than full screen. Then, when the new window is generated, reposition the windows so you can see 
the smaller, new window when the main window is in front. (If you lose a window behind another, 
use the browser's Window menu to choose the hidden window.) The key point of Listing 10-1 is 
that the newWindow variable is defined as a global variable so that both the makeNewWi ndow( ) 
and cl oseNewWi ndow( ) functions have access to it. When a variable is declared with no value 
assignment, its initial value is nuT 1 . A nul 1 value is interpreted to be the same as f al se in a condi- 
tion, whereas the presence of any nonzero value is the same as true in a condition. Therefore, in the 
closeNewWindowO function, the condition tests whether the window has been created before issu- 
ing the subwindow's cl ose( ) method. Then, to clean up, the function sets the newWi ndow variable 
to n U 1 1 so that another click of the Close button doesn't try to close a nonexistent window. 

Note 

The property assignment event-handling technique employed throughout the code in this chapter, and much of 
the book, is addEvent( ), a cross-browser event handler explained in detail in Chapter 32, "Event Objects." 

The addEvent( ) function is part of the script file jsb global . js, located on the accompanying CD-ROM 
in the Content / folder where it is accessible to all chapters' scripts. ■ 



LISTING 10-1 



References to Window Objects 

HTML: jsb-10-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Wi ndow Open & Cl ose</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 10-01 . j s "></scri pt> 

</head> 

<body> 

<hl>Window Open & Close</hl> 
<f orm> 
<P> 

<input type="button" i d="create-wi ndow" val ue="Create New Window"> 
<input type="button" i d="cl ose-wi ndow" value="Close New Window") 

</p> 
</ f orm> 



138 



Chapter 10: Window and Document Objects 



</body> 
</html > 

JavaScript: jsb-10-01.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to critical elements 

var oButtonCreate = document . getEl ementBy Id (' create-wi ndow ') ; 
var oButtonClose = document . getEl ementBy Id (' cl ose-wi ndow ') ; 

// if they al I exi st . . . 

if (oButtonCreate && oButtonClose) 
{ 

// apply behaviors 

oButtonCreate . oncl i ck = makeNewWindow; 
oButtonCl ose . oncl i ck = cl oseNewWi ndow ; 

I 

I 

} 

var newWindow; 

function makeNewWindow( ) 
{ 

newWindow = wi ndow . open ("","", "hei ght=300 ,wi dth=300" ) ; 

} 

function cl oseNewWindow( ) 
{ 

if (newWindow) 
{ 

newWi ndow . cl ose ( ) ; 
newWi ndow = null; 



window Properties and Methods 

The three methods for the wi ndow object described in this section have an immediate impact on user 
interaction by displaying dialog boxes of various types. They work with all scriptable browsers. You 
can find extensive code examples in Part IV for each property and method. You can also experiment 
with the one-statement script examples by entering them in the top text box of The Evaluator Jr. (from 
Chapter 8, "Programming Fundamentals, Part I"). 



139 



Part II: JavaScript Tutorial 



One of the first questions that new scripters ask is how to customize the title bars, sizes, and button 
labels of these dialog boxes. Each browser maker dictates how these dialogs are labeled. Because trick- 
sters have tried to use these dialog boxes for nefarious purposes over the years, browser makers now 
go to great lengths to let users know that the dialog boxes emanate from web page scripts. Scripters 
cannot alter the user interfaces of these dialog boxes. 

window. alert() method 

We use the al ert( ) method many times in this tutorial. This window method generates a dialog 
box that displays whatever text you pass as a parameter (see Figure 10-2). A single OK button (whose 
label you cannot change) enables the user to dismiss the alert. 



FIGURE 10-2 



A JavaScript alert dialog box. 







■ 01 









All three dialog-box methods are good cases for using a wi ndow object's methods without the ref- 
erence to the window. Even though the al ert ( ) method technically is a wi ndow object method, 
no special relationship exists between the dialog box and the window that generates it. In production 
scripts, we usually use the shortcut reference: 

alert("This is a JavaScript alert dialog."); 

window. confirm() method 

The second style of dialog box presents two buttons (Cancel and OK in most versions on most plat- 
forms) and is called a confirm dialog box (see Figure 10-3). More important, this is one of those 
methods that returns a value: true if the user clicks OK or f al se if the user clicks Cancel. You can 
use this dialog box and its returned value as a way to have a user make a decision about how a script 
progresses. 



FIGURE 10-3 



A JavaScript confirm dialog box (IE7AVinXP style). 
7 I An tn -are fii wn e> Hit ncrf 



Because the method always returns a Boolean value, you can use the evaluated value of the entire 
method as a condition statement in an i f or i f . . . el se construction. For example, in the following 



140 



Chapter 10: Window and Document Objects 



code fragment, the user is asked about starting the application over. Doing so causes the i ndex . html 
page to load into the browser. 

if ( conf i rm( " Are you sure you want to start over?")) 
{ 

1 ocati on . h ref = "index.html"; 

} 

window. prompt() method 

The final dialog box of the wi ndow object, the prompt dialog box (see Figure 10-4), displays 
a message that you set and provides a text field for the user to enter a response. Two buttons, 
Cancel and OK, enable the user to dismiss the dialog box with two opposite expectations: canceling 
the entire operation or accepting the input typed in the dialog box. 



FIGURE 10-4 



A JavaScript prompt dialog box (Safari 2 style). 



JwaSc i pi 



fii •* -,jNr tar hs* 















The wi ndow . prompt ( ) method has two parameters. The first is the message that acts as a prompt to 
the user. You can suggest a default answer in the text field by including a string as the second param- 
eter. If you don't want any default answer to appear, include an empty string (two double quotes 
without any space between them). 

This method returns one value when the user clicks either button. A click of the Cancel button 
returns a value of null, regardless of what the user types in the field. A click of the OK button 
returns a string value of the typed entry. Your scripts can use this information in conditions for i f 
and if. . .else constructions. A value of n u 1 1 is treated as f a 1 s e in a condition. It turns out that 
an empty string is also treated as f al se. Therefore, a condition can easily test for the presence of real 
characters typed in the field to simplify a conditional test, as shown in the following fragment: 

var answer = prompt("What is your name?",""); 

if (answer) 

{ 

alert(" Hello, " + answer + "!"); 

} 

In this example, the only time the al ert( ) method is called is when the user enters something in 
the prompt dialog box and clicks the OK button. 

load event 

The wi ndow object reacts to several system and user events, but the one you will probably use most 
often is the event that fires as soon as everything in a page finishes loading. This event waits for 



141 



Part II: JavaScript Tutorial 



images, Java applets, and data files for plug-ins to download fully to the browser. It can be dangerous 
to script access to elements of a document object while the page loads because if the object has not 
loaded yet (perhaps due to a slow network connection or server), a script error results. The advantage 
of using the load event to invoke functions is that you are assured that all document objects are in 
the browser's DOM. 

The load event handler can be applied to the wi ndow object in several ways, depending on the 
browser and the circumstances: 

wi ndow . addEvent Li stener ( ' 1 oad ' , f uncti onName , false); 
window.attachEvent( 'onload' , f uncti onName) ; 

where f uncti onName is the function you've written that you want to run as soon as 
the page has downloaded. (For a cross-browser event-adding function, see Chapter 32.) 
addEventLi stener and attachEvent can be called multiple times to add more than one 
function to the list to be executed when the page has loaded. 

You can also apply the behavior directly to the element: 

wi ndow[ ' onl oad ' ] = f uncti onName ; 
wi ndow . onl oad = f uncti onName ; 

However, this usage dictates that there will be only one function to run when the page is loaded, 
replacing any event handler already assigned to the wi ndow object. 

In old-school legacy web pages, you'll sometimes find the window event handler applied to the body 
element right in the HTML: 

<body onload="functionName()"> 

(Even though you will come to associate the <body> tag's attributes with the document object's 
properties, it is the wi ndow object's event handlers that go inside the tag.) This embedding of 
JavaScript into the fabric of the HTML is considered poor usage today for several reasons: it doesn't 
let browsers that can't handle the scripting fail gracefully, it makes the HTML file heavier than it has 
to be, and it makes both the script and the markup messier and more time-consuming to modify. 
Separation of layers is the way to go. 

Cross-Reference 

For more on the wi ndow. onload event, see Chapter 27, "Window and Frame Objects." ■ 



The location Object 

Sometimes an object in the hierarchy represents something that doesn't seem to have the kind of phys- 
ical presence that a window or a button does. That's the case with the location object. This object 
represents the URL loaded into the window. This differs from the document object (discussed later in 
this lesson): the document is the content of the page, while the location is its URL (Uniform Resource 
Locator or address). 

A URL consists of many components that define the address and method of data transfer 

for a file. Pieces of a URL include the protocol (such as http:) and the hostname (such as 

www . exampl e . com). You can access all these items as properties of the location object. For the 



142 



Chapter 10: Window and Document Objects 



most part, though, your scripts will be interested in only one property: the href property, which 
defines the complete URL. 

Setting the I oca ti on . href property is the primary way your scripts navigate to other pages: 

I ocati on . href = "http://www.example.com/contact.html"; 

For pages outside the domain of the current page, you need to specify the complete URL. You 
can generally navigate to a page in your own web site by specifying a relative URL (that is, 
relative to the currently loaded page) rather than the complete URL with protocol and host 
information. 

I ocati on . href = "contact.html"; // relative URL 

If the page to be loaded is in another window or frame, the window reference must be part of the 
statement. For example, if your script opens a new window and assigns its reference to a variable 
named newWindow, the statement that loads a page into the subwindow is 

newWi ndow . 1 ocati on . h ref = "http://www.example.com"; 



The navigator Object 

Despite a name reminiscent of the Netscape Navigator-branded browser, the navigator object is 
implemented in all scriptable browsers. All browsers also implement a handful of properties that 
reveal the same kind of information that browsers send to servers with each page request. Thus, the 
navi gator. userAgent property returns a string with numerous details about the browser and 
operating system. For example, a script running in Internet Explorer 8 in Windows XP receives the 
following value for the navi gator . userAgent property: 

Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1) 
The same script running in Firefox 3.5.2 on a Macintosh reveals the following userAgent details: 

Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.1.2) 
Gecko/20090729 Fi ref ox/3 . 5 . 2 

Cross-Reference 

See Chapter 42, "Navigator and Other Environment Objects" (on the CD), for more details about the 
navigator object and the meaning of the values returned by its properties. Unfortunately, it cannot be 
trusted to accurately report the actual user agent make, model, and version. It once was used extensively 
to branch script execution according to various browser versions. Chapter 25, "Document Object Model 
Essentials," describes more modern ways to detect the capabilities of the browser. ■ 



The document Object 

The document object holds the real content of the page. Properties and methods of the document 
object generally affect the look and content of the document that occupies the window. As you saw 
in Chapter 5, "Your First JavaScript Script," all W3C DOM-compatible browsers allow script access 



143 



Part II: JavaScript Tutorial 



to the text contents of a page when the document has loaded. You've also seen that DOM methods 
let a script create content dynamically after the page has loaded. Many document object properties 
are arrays of other objects in the document, which provide additional ways to reference these objects 
(over and above the document . get El ementBy Id ( ) method). 

Accessing a document object's properties and methods is straightforward, as shown in the following 
syntax examples: 

[wi ndow . ] document . propertyName 

[wi ndow. ] document . methodNamei [parameters^ ) 

The wi ndow reference is optional when the script is accessing the document object that contains the 
script. If you want a preview of the long list of document object properties of IE or a Mozilla-based 
browser, enter document in the object text box of The Evaluator Jr. and press Enter/Return. The 
object's properties, current values, and value types appear in the Results box (as well as methods in 
Mozilla). Following are some of the most commonly used properties and methods of the document 
object. 



document. getEIementByldO method 

You met the document . getEl ementById( ) method in Chapter 5 when learning about the syntax 
for referencing element objects. This W3C DOM method is one you will use a lot. Get to know its 
finger-twisting name well. Be sure to honor the upper- and lowercase spelling of this all-important 
method. 

The sole parameter of this method is a quoted string containing the ID of the element you wish to 
reference. The Evaluator Jr. page from Chapter 8 (and in the listings on the CD-ROM) has several 
element objects with IDs, including input, output, and inspector. Type this method in the top 
text box with each ID, as in the following example: 

doc ument. getEl ement By Id(" output") 

The method returns a value, which you typically preserve in a variable for use by subsequent script 
statements — for example: 

var oneTable = document . getEl ementById( "sal esResul ts" ) ; 

After the assignment statement, the variable represents the element object, allowing you to get and set 
its properties or invoke whatever methods belong to that type of object. 



document.getElementsByTagNameO method 

getEl ementsByTagName ( ) is a handy method for collecting an array of page elements that share 
the same tag name. For example, to get a list of all of the images on the page, we could call: 

var almages = document . get El ementsByTagName (' i mg ') ; 

Referring to an image by its position in an array of all images can be challenging — for example, if 
we want to work with an image gallery on a page that also contains miscellaneous images before and 
after the gallery. One of the advantages of using getEl erne nts By TagName() is that it can gather a 
collection within any container element on the page: 



144 



Chapter 10: Window and Document Objects 



HTML: 

<div i d= " ga 1 1 e ry " > 

<h2>My Gallery</h2> 

<img s rc=" bat . j pg " alt="bat"> 

<img s rc=" cat . j pg " alt="cat"> 

<img s rc=" hat . j pg " alt="hat"> 
</div> 

JavaScri pt : 

var oGallery = document . getEl ementById( ' gal 1 ery ') ; 

var aCollection = oGal 1 ery . getEl ementsByTagName( ' img ') ; 

The array aCollection() in this example then contains the three image objects (but not, of course, 
the h2 element). As you'll recall from the discussion of arrays in Chapter 9, "Programming Funda- 
mentals, Part II," an index number inside an array's square brackets points to one of the elements in 
the array. To find out how many objects are in the collection, use 

aCollection. length 
Each object can be accessed by its offset into the array: 

olmage = almages[0]; // first image 
olmage = a Images C 1 ] ; // second image 

Other applications of this method might be to collect all the items in a list, all the hyperlinks 
(anchors) in a text block, or all the multimedia objects on a page. 



document.forms[] property 

Implemented back in pre-DOM days, the document . forms property of the document object con- 
tains an array of all form element objects in the document. Compare these two expressions: 

var aForms = document . forms ; 

var aForms = document . get El ementsByTagName (' form ') ; 

One important difference is that the document, forms collection enables us to reference a particular 
form directly by its name, not just by its offset in the array. It isn't always practical to refer to a form 
by its index number. A dynamic web page might contain a varying number of forms depending on 
context, so the position of any one form on the page might change with circumstances. For example, 
a Search form that sits in the header chrome of every page of a web site might be suppressed on the 
Advanced Search page; a Join List form might be suppressed on the Contact page; and a page listing 
workshops might blossom with registration forms for selected workshops. 

Scrip table browsers let you refer to a form more directly by its name or ID (that is, the identifier 
assigned to either the name or i d attribute of the <f orm> tag): 

<form id=" formld" name=" formName" ...> 

The first way is by using the getEl ementById( ) method: 

document. get El ementBy Id ( " form Id" ) 



145 



Part II: JavaScript Tutorial 



The second way uses array syntax, applying the form's name or ID as a string index value of the array: 

document.formsf" form Id" ] 
document . forms [ " formName" ] 

A third, even shorter way to refer to a form object by name is to append the name as a property of 
the document object, as in: 

document. formName 

However, this last technique works only if the name attribute omits several characters that are legal in 
HTML element names but illegal in JavaScript object names such as hyphen (-), period (.), and colon 
(:). (For more on this point, see Chapter 6.) 

Any of these methodologies reaches the same object. We will primarily be using the DOM methods 
getEl ementById( ) and getEl ementsByf agName( ) throughout this book; however, the doc- 
ument . forms collection syntax, which dates back to the earliest scnptable browsers, is still valid in 
the most modern versions. 

document. images[] property 

Just as a document keeps track of forms in a special array property, the document object maintains 
a collection (array) of images inserted into the document by way of <img> tags. Images referenced 
through the document, images array may be reached by either numeric or string index of the i mg 
element's name. Just as with forms, the name attribute value is the identifier you use for a string 
index. 

The presence of the document . i mages property indicates that the browser supports image objects 
and therefore scripting techniques such as image-swapping. Thus, you can use the existence of the 
property as a test condition to make sure the browser supports images as objects before attempting to 
perform any script action on an image. To do so, surround statements that deal with images with an 
i f construction that verifies the property's existence, as follows: 

if ( document . i mages ) 

{ 

// statements dealing with img objects 

} 

Older browsers skip the nested statements, preventing them from displaying error messages to their 
users. 

In a typical, complex web page today, there are images in different sections used for very 
different purposes, and it doesn't often make sense to collect all the images on a page 
in a single array. In cases like this, it might be more convenient to use the DOM method 
getEl ementsByTagName( ) instead (see above). 

document. createEIement() and document.createTextNode() 
methods 

Adding a new element to an HTML document consists of, at minimum, two steps: 

1 . Create the new element for the document. 

2. Insert it exactly where you want it within the tree structure of the page. 



146 



Chapter 10: Window and Document Objects 



The document . createEl ement( ) method lets you create a brand-new element object in the 
browser's memory. To specify the element you wish to create, pass the tag name of the element as a 
string parameter of the method: 

var newEletn = document . createEl ement( "p" ) ; 

You may also want to add some attribute values to the element, which you may do by assigning values 
to the newly created object's properties, even before the element becomes part of the document. 

new El em . setAtt ri bute ( " cl ass " , " i ntro" ) ; 
This element can be inserted wherever you want in the document — for example, at the end: 

document. body. appendChild(new El em); 
These three lines of code generate a paragraph at the end of the document body: 

<body> 

<p class = "intro"X/p></body> 

As you saw in the object hierarchy illustrations in Chapter 6, "Browser and Document Objects," an 
element object frequently needs text content between its start and end tags. The W3C DOM way 
to create that text is to generate a brand new text node via the document . createTextNode( ) 
method and populate the node with the desired text. For example: 

var newText = document . createTextNode( "Greeti ngs to all."); 
newElem.appendChild ( newText ) ; 

resulting in: 

<body> 

<p cl ass=" i ntro" >Greeti ngs to all .</p></body> 

As you can see, the act of creating an element or text node does not by itself influence the document 
node tree. You must invoke one of the various insertion or replacement methods to place the new text 
node in its element and place the element in the document, as you learned how to do in Chapter 5. 

document. write() method 

The document . wri te ( ) method is another way of writing content to a document. It has the advan- 
tage of being "quick and dirty," but it also has several disadvantages: 

• document, w r i t e ( ) can add a piece of a web page only while the page is loading into the 
browser the first time. Any subsequent invocation of the method replaces the entire page. 

• Because document, w r i t e ( ) will insert any old block of text into the document, it enables 
sloppy programming habits and malformed markup, encourages the mixture of markup with 
content in scripting, and does not encourage the separation of development layers (structure 
from content). 

• document. write( ) does not work with XHTML, a document type that doesn't permit its 
content to be modified during the initial parsing. 



147 



Part II: JavaScript Tutorial 



For these reasons we do not recommend that you use document . wri te( ) in your own code, 
though it's still useful to understand how it works in order to be able to read legacy code. 

The document. write( ) method operates both in immediate scripts to create content in a page as 
it loads and in deferred scripts that create new content in the same window or in a different window. 
The method requires one string parameter, the HTML content to be written to the window or frame. 
Such string parameters can be variables or any other expressions that evaluate to a string. Very often, 
the written content includes HTML tags. 

Bear in mind that after a page loads, the browser's output stream automatically closes. After that, any 
document, wri te( ) method issued to the current page opens a new stream that immediately erases 
the current page (along with any variables or other values in the original document). Therefore, if you 
wish to replace the current page with script-generated HTML, you need to accumulate that HTML in a 
variable and perform the writing with just one document. write( ) method. You don't have to clear 
a document explicitly and open a new data stream; one document . wri te ( ) call does it all. 

One last piece of housekeeping advice about the document.wri te( ) method involves its compan- 
ion method, document . cl ose ( ) . Your script must close the output stream when it finishes writing 
its content to the window (either the same window or another). After the last document. write( ) 
method in a deferred script, be sure to include a document. closeO method. Failure to do this 
may cause images and forms not to appear. Also, any document .wri te( ) method invoked later 
will only append to the page, rather than clear the existing content to write anew. 

To demonstrate the document. write( ) method, we show two versions of the same application. 
One writes to the same document that contains the script; the other writes to a separate window. Type 
the code for each document in a new text editor file, save them, and open the .html file in your 
browser. 

Listing 10-2 creates a button that assembles new HTML content for a document, including HTML tags 
for new document title and color attributes for the <body> tag. An operator in the listing that may be 
unfamiliar to you is +=. It appends a string on its right side to whatever string is stored in the variable 
on its left side. This operator is a convenient way to accumulate a long string across several separate 
statements. With the content gathered in the newContent variable, one document .wri te( ) state- 
ment blasts the entire new content to the same document, obliterating all vestiges of the content of 
Listing 10-2. The document . cl ose( ) statement, however, is required to close the output stream 
properly. When you load this document and click the button, notice that the document title in the 
browser's title bar changes accordingly. As you click back to the original and try the button again, 
notice that the dynamically written second page loads much faster than even a reload of the original 
document. 



LISTING 10-2 



Using document.writeO on the Current Window 



HTML: jsb-10-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Wri ti ng to Same Doc</title> 



148 



Chapter 10: Window and Document Objects 



<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 10-02 . j s "></scri pt> 

</head> 

<body> 

<hl>Wri ting to Same Doc</hl> 
<f orm> 
<P> 

<input type="button" id="rewritePage" val ue="Repl ace Content") 
</p> 
</ f orm> 
</body> 
</html > 



JavaScript: jsb-1002.js 



// replace the page with new markup 
f uncti on reWri te ( ) 



// assemble content for new window 
var newContent = '<!D0CTYPE html>'; 
newContent += '<html>'; 
newContent += '<head>'; 

newContent += '<meta http-equi v="content-type" 

content="text/html ; charset=utf -8"> ' ; 
newContent += '<title>A New Doc</ti tl e> ' ; 
newContent += '<style type="text/css">' ; 
newContent += 'body ( background-color: aqua; )'; 
newContent += '</style>'; 
newContent += '</head>'; 
newContent += '<body>'; 

newContent += '<hl>This document is brand new.</hl>'; 

newContent += '<p>Click the Back button to see the original document . </p> ' 
newContent += '</body>'; 
newContent += ' </html > ' ; 



// write HTML to new window document 

document . wri te ( newContent ) ; 

document . cl ose () ; // close layout stream 

} 



// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld) 

{ 

// point to the button 

var oButtonRewri te = document . getEl ementByld (' rewri tePage ') ; 



// if it exi sts . . . 
if (oButtonRewrite) 



continued 



149 



Part II: JavaScript Tutorial 



LISTING 10-2 



(continued) 



II apply event handler 
addEvent( oButtonRewri te , 



'click' , reWri te ) 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 



In Listing 10-3, the situation is a bit more complex because the script generates a subwindow to 
which an entirely script-generated document is written. 

Note 

You will have to turn off pop-up window blocking temporarily to run this script. ■ 

To keep the reference to the new window alive across both functions, the newWi ndow variable is 
declared as a global variable. As soon as the page loads, the onl oad event handler invokes the mak- 
eNewWi ndow( ) function. This function generates a blank subwindow. We added a property to the 
third parameter of the window.open( ) method that instructs the status bar of the subwindow to 
appear. 

A button in the page invokes the subwri te( ) method. The first task it performs is to check the 
cl osed property of the subwindow. This property returns true if the referenced window is closed. 
If that's the case (if the user closed the window manually), the function invokes the ma keNewWi n - 
dow( ) function again to reopen that window. 

With the window open, new content is assembled as a string variable. As with Listing 10-2, the 
content is written in one blast (although this isn't necessary for a separate window), followed by a 
cl ose( ) method. But notice an important difference: Both the write ( ) and closeO methods 
explicitly specify the subwindow. 



LISTING 10-3 



Using document.writeO on Another Window 



HTML: jsb-10-03.html 



<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Wri ti ng to Subwi ndow</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 10-03 . j s "></scri pt> 

</head> 

<body> 

<hl>Wri ting to Subwi ndow</hl> 
<f orm> 



150 



Chapter 10: Window and Document Objects 



<p> 

<input type="button" i d="wri teSubwi ndow" value="Write to Subwindow"> 
</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-10-03.js 

var newWindow; 

function makeNewWindow( ) 
{ 

newWi ndow = wind ow. open( status, height=200, width =3 00"); 

} 

f uncti on subWri te ( ) 
{ 

// make new window if someone has closed it 

if (InewWindow || newWi ndow . cl osed ) 

{ 

makeNewWindow( ) ; 

} 

// bring subwindow to front 
newWi ndow . focus ( ) ; 

// assemble content for new window 
var newContent = '<!D0CTYPE html>'; 
newContent += '<html>'; 
newContent += '<head>'; 

newContent += '<meta http-equi v="content-type" 

content="text/html ; charset=utf -8"> ' ; 
newContent += '<title>A New Doc</ti tl e> ' ; 
newContent += '<style type="text/css "> ' ; 
newContent += 'body j background-color: aqua; ('; 
newContent += '</style>'; 
newContent += '</head>'; 
newContent += '<body>'; 

newContent += '<hl>This document is brand new.</hl>'; 
newContent += '</body>'; 
newContent += '</html>'; 

// write HTML to new window document 
newWi ndow .document . wri te ( newContent ) ; 

// close layout stream 
newWi ndow .document . cl ose ( ) ; 

} 

// apply behaviors when document has loaded 
f uncti on i ni ti al i ze ( ) 

continued 



151 



Part II: JavaScript Tutorial 



(continued) 



II do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to the button 

var oButtonRewri te = document . getEl ementBy Id (' wri teSubwi ndow ') ; 

// if it exi sts . . . 

if (oButtonRewrite) 
{ 

// apply event handler 

addEvent(oButtonRewrite, 'click', subWrite); 

1 

1 

1 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 
addEvent(wi ndow, 'load', makeNewWi ndow) ; 



The next logical step after the document level in the object hierarchy is the form. That's where you 
will spend the next lesson. 



Exercises 



1 . Which of the following references are valid, and which are not? Explain what is wrong with the 
invalid references. 

a. wi ndow . document . form[0] 

b. sel f . entry Form . submi t ( ) 

c. document . forms [2] . name 

d. document . getEl ement By ID("firstParagraph") 

e. newWi ndow . document . wri te (" Howdy " ) 

2. Write the JavaScript statement that displays an (annoying) dialog box welcoming visitors to 
your web page. 

3. Write the JavaScript statement that executes while the page loads to display the same message 
from Question 2 to the document as an < h 1 > -level headline on the page. 

4. Create a page that prompts the user for his or her name as the page loads (via a dialog box) and 
then welcomes the user by name in the body of the page. 

5. Create a page with any content you like, but one that automatically displays a dialog box after 
the page loads to show the user the URL of the current page. 



152 



Forms and Form 
Elements 



CHAPTER 



M 



ost interactivity between a web page and the user takes place inside a 
form. That's where a lot of the interactive HTML stuff lives for every 
browser: text fields, buttons, checkboxes, option lists, and so on. 

In this chapter, we discuss how to locate forms and their controls in the docu- 
ment tree, how to change them, how to examine the user's input, and how to 
submit a form or suppress submission if the input doesn't validate. 



The Form object 



A form and the input controls that go inside it are DOM objects with unique 
properties that other objects in the document don't have. For example, a form 
object has an action property that tells the browser where to send input values 
when a form is submitted. A sel ect control (drop-down list) has a selecte- 
d I ndex property that tells us which option has been selected by the user. 

Our first step is to point to the form on the page. Here are three ways of doing 
this, all referring to the following abbreviated snippet of a page that contains 
three forms: 



<div id="header"> 

<form id="search" action=".. 

<form i d = " j o i n - 1 1st" action = 
</div> 

<form id="contact" action=". 



">. . . </form> 
'...">...</ form> 



'>. . .</form> 



IN THIS CHAPTER 



What the form object 
represents 

How to access key form object 
properties and methods 

How text, button, and select 
objects work 

How to submit forms from 
a script 

How to pass information from 
form elements to functions 



1. The DOM method getEl ementByldt ), as described in previous 

chapters, gives us a handle on a single, specific element on the page if we 
know its i d attribute: 



var oForm = document . getEl ementById( ' search ' 



153 



Part II: JavaScript Tutorial 



In practice, using getElementByldO suffices most of the time because web pages generally 
contain one or a very small number of unique forms which accomplish very different tasks; 
assigning them unique IDs in the markup is a natural. 

2 . The DOM method getElementsByTagName( ) delivers an array or collection of form 
objects with a given tag name: 

var aForms = document . getEl ementsByTagName (' form ') ; 

var oForm = aFormsfO]; // get the first form on the page 

As always, JavaScript arrays begin with the first item having an index of zero, so our collection 
of three forms can be addressed as array elements 0,1, and 2. 

It's worth pondering the usefulness of working with a collection of all the forms on a 
page. In order to locate a specific form from the collection, we would have to know 
its position among all the forms on the page (which could change in a rich, dynamic 
site) or we'd have to cycle through them looking for an identifier (which suggests using 
getEl ementBy Id ( ) in the first place). 

One of the cool things about getEl erne nts By TagNa me ( ) is that it can give us a collection 
of obj ects within a particular parent other than the document element itself: 

var oHeader = document . getEl ementBy Id (' header ') ; 
var aForms = oHeader . get El ementsByTagName (' form ') ; 
var oForm = aFormsfO] ; 

In this example, we're collecting all the forms in the "header" section of the document only. 

Or imagine a page listing a series of workshops, each of which has its own separate registration 
form. We could collect an array of all those registration forms by first pointing to their parent 
d i v without worrying about other miscellaneous forms on the page confusing the mix. 

3 . The syntax document. forms is another way of collecting all the forms on the page that 
pre-dates today's DOM methods but is still supported by modern browsers, so as not to break 
legacy web sites. 

var aForms = document . forms ; 
// then point to one form: 
var oForm = aFormsfO] ; 
// or: 

var oForm = a Forms [ " sea rch " ] ; 
// or: 

var oForm = aForms . search ; 

Using this original "DOM Level 0" syntax, we can reference a f o rm object either by its position 
in the array of forms contained in a document or by name (if you assign an identifier to the i d 
or name attribute inside the <f o rm> tag). If only one form appears in the document, it is still 
a member of an array (a one-element array) and is referenced as follows: 

document . forms [0] 

Or use the string of the element's name as the array index: 
document . forms [ formNamel 



154 



Chapter 11 : Forms and Form Elements 



Notice that the array reference uses the plural version of the word, followed by a set of square 
brackets containing the index number (zero is always first) or name of the element. Alterna- 
tively, you can use the form's name (not as a quoted string) as though it were a property of the 
document object: 

document . formName 

However, this last syntax works only if the form i d or name doesn't include characters such 
as hyphens, periods, or colons that would confuse JavaScript. For example, the second form in 
our sample HTML above has the i d of j o i n - 1 i s t : 

var oForm = document . forms . j oi n -I i st ; 

This looks to JavaScript like we're trying to subtract the value of a variable named list from a 
form object with the id of join. This statement would either stop JavaScript cold or produce 
a result of N a N (Not a Number). As a general rule, we recommend that you use syntax that puts 
element names in quotes. 

Because there are so many ways to arrive at a form object, we'll often represent them in further 
examples with the label f o r m 0 b j e c t . 



Form as object and container 

Because the modern DOM is backward-compatible with many of yesterday's conventions, the form 
object finds itself the matriarch of two different family trees at the same time. The modem DOM Level 
2 specifies that the form is the parent of all of its child nodes, both element and text nodes, whereas 
the older DOM Level 0 makes the form the container for all of its form control objects only (input, 
select, button, and textarea elements). Figure 11-1 shows the structure of this DOM 0 hierar- 
chy and its place relative to the document object. You'll see the effect this structure has on the way 
you reference form control elements in a moment. 



FIGURE 11-1 



DOM Level 0 hierarchy for forms and controls. 



window 



text 



document 




form 



TTT 



radio 



I I I 



button 



select 



textarea 



checkbox 



reset 



option 



password 



hidden 



submit 



155 



Part II: JavaScript Tutorial 



Let's illustrate the difference by diagramming the following snippet of HTML: 



LISTING 11-1 



Sample form markup 

<form acti on="search . php" method="post"> 

<P> 

<label f or=" i nputSea rch ">Sea rch for:</label> 

<input i d=" i nputSea rch " name=" i nputSea rch " type="text" value=""> 
<input id="submit" type="submi t" val ue="Search"> 

</p> 
</f orm> 



Figure 11-2 shows the DOM Level 2 tree for this markup. Note that it represents the entire content of 
that segment of the document. The carriage returns, tabs, and spaces between elements are text nodes 
(represented here by the shorthand " [whi tespace] "). 



FIGURE 11-2 



DOM Level 2 tree for a typical form. 





form 
















"[whitespace]" 




) 


"[whitespace]" 



"[whitespace]" 



label 



'[whitespace]" 



input 
(text) 



'[whitespace]" 



input 
{submit) 



'[whitespace]' 



"Search for:" 



Figure 11-3 shows the DOM Level 0 tree for this same form. It includes only the input controls and 
omits the paragraph, the label, and the text nodes. 



FIGURE 11-3 



DOM Level 0 tree for the same form. 



form 



input 
(text) 



156 



input 
(submit) 



Chapter 11 : Forms and Form Elements 



These two object trees are clearly useful for very different purposes. The DOM Level 2 tree can be 
used to read and write the entire document content with fine granularity. The DOM Level 0 tree 
makes it quick and easy to read and write the form controls only. 

Please note that whether you're using DOM 0 or DOM 2 techniques in any given statement, the 
objects are the same. For example, 

var oForm = document . get El ementBy Id (' my Form ') ; 
var oControl = oForm . f ri tzy ; 

is perfectly valid JavaScript and will work fine if f ri tzy is the ID of an input control inside the form 
my Form. 

In addition to a large collection of properties and methods it has in common with all HTML element 
objects, the form object features a number of items that are unique to this object. Almost all of these 
unique properties are scripted representations of the form element's attributes (act i on, target, 
and so on). Scnptable browsers allow scripts to change these properties under script control, which 
gives your scripts potentially significant power to direct the behavior of a form submission in response 
to user selections on the page. 

Accessing form properties 

Forms can be created from standard markup tags in the HTML page or by using DOM methods in 
JavaScript. Either way, you can set attributes such as name, target, acti on, method, and enc- 
type. Each of these is a property of a form object, accessed by all lowercase versions of those words, 
as in: 

var sURL = formObject. acti on ; 
To change any of these properties, simply assign new values to them: 

formObject . action = "http: //www . exampl e . com/cgi /I ogin.pl " ; 
These last two JavaScript statements could be re-stated using compound object references: 

var sURL = document . getEl ementBy Id (' formName '). acti on ; 
document.forms[0].action = "http: / /www .example. com/cgi /log in. pi " ; 

However, combining multiple operations into a single expression doesn't allow the script to test for 
validity along the way. Separating steps and testing as we go is a more bulletproof way to code: 

var oForm = document . getEl ementBy Id ('formName'); 
if ( ! oForm) 
{ 

// do something if the named form isn't found 

} 

var sURL = oForm . acti on ; 

form. elements!] property 

The elements[] property is a collection of all the input controls within a form. This is another array 
with items listed in the order their HTML tags appear in the source code. It is generally more effi- 
cient to refer to a single element directly using its ID, but sometimes a script needs to look through all 



157 



Part II: JavaScript Tutorial 



of the elements in a form. For example, a form-validation routine might loop through every element 
checking to make sure that its value has been entered correctly by the user. A loop like that might not 
need to look at the text nodes and other elements that aren't form controls, and in fact it would have 
to perform a series of tests on each element it encountered to determine whether it were a control. In 
a case like this, using the el ements [ ] collection is vastly more efficient. 

The following code fragment shows the form.elements[] property at work in a for repeat loop 
that looks at every control element in a form to set the contents of text fields to an empty string. 
The script cannot simply barge through the form and set every element's content to an empty string 
because some elements may be types (for example, a button) whose val ue properties have different 
purposes. 

var oForm = document . getEl ementBy Id (' regi strati on-form ') ; 
if (loForm) return false; 

for (var i = 0; i < oForm. el ements . 1 ength ; i++) 

{ 

if (oForm.el ements[i ] .type == "text") 
1 

oForm . el ements [i ]. val ue = ""; 

} 

} 

In the first statement, we create the variable oForm that holds a reference to the desired form. We do 
this so that when we make many references to form elements later in the script, the typical length of 
each reference is much shorter (and marginally faster). We can use the oForm variable as a shortcut 
to building references to items more deeply nested in the form. 

Next, we start looping through the items in the el ements array for the form. Each form control 
element has a type property, which reveals what kind of form control it is: text, button, radio, check- 
box, textarea, and so on. We're interested in finding elements whose type is text. For each of those, 
we set the val ue property to an empty string. 

We're permitting compound expressions such as oForm.elements[i].typein this case because, 
having already tested to make sure the form exists, we can trust the DOM to deliver us a valid form 
control object with each iteration of the el ements [ ] collection. Even if the form were empty of con- 
trols, the script wouldn't fail; if the el ements [ ] collection were an empty array, the for loop above 
would simply terminate before its first iteration with no error because oForm.elements.length 
would be zero. 

We'll return to forms later in this chapter to show you how to submit a form without a Submit button 
and how client-side form validation works. 



Form Controls as Objects 

Three kinds of HTML elements nested inside a <f orm> tag become scriptable objects in all browser 
DOMs. Most of the objects owe their existence to the <i nput> tag in the page's source code. Only 
the value assigned to the type attribute of an <i nput> tag determines whether the element is a text 
box, password entry field, hidden field, button, checkbox, or radio button. The other two kinds of 
form controls, textarea and sel ect, have their own tags. 



158 



Chapter 11 : Forms and Form Elements 



To reference a particular form control as an object, you can point directly to it using its i d or 
tagName with DOM Level 2 methods, or, using DOM Level 0 syntax, build a reference as a hierarchy 
starting with the document, through the form, and then to the control. You've already seen how 
many ways you can reference merely the form part — all of which are valid for building form control 
references. But if you are using only the identifiers assigned to the form and form control elements 
(rather than the associated arrays of elements), the syntax is as follows: 

document. get El ementBy Id ( control Name) 

or 

document . formName. control Name 
For example, consider the following simple form: 



<form i d=" sea rch Form" acti on="cgi -bi n/search . pi "> 

<P> 

<input type="text" id="entry" name="entry"> 

<input type="submi t" id="sender" name="sender" val ue="Search"> 

</p> 
</ form) 

The following sample references to the text input control are all valid: 



docume nt.getElement By Id ( " entry") 

document. searchForm. entry 

docume nt.searchForm. el ements [0] 

document . forms [ "searchForm" ]. el ements [ "entry "] 

document . forms [ "searchForm" ]. entry 

Although form controls have several properties in common, some properties are unique to a particu- 
lar control type or to related types. For example, only a select object offers a property that reveals 
which item in its list is currently selected. Checkboxes and radio buttons both have a property that 
indicates whether the control is currently set to on. Similarly, all text-oriented controls operate the 
same way for reading and modifying their content. 

Having a good grasp of the scriptable features of form control objects is important to your success 
with JavaScript. In the next sections, you meet the most important form control objects and see how 
scripts interact with them. 



Text-related input objects 

Each of the four text-related HTML form elements — input elements of the text, password, 
and hidden types, plus the textarea element — is an element in the document object 
hierarchy. All but the hidden types are normally displayed on the page, enabling users to enter text 
and select options. 

To make these form control objects scriptable in a page, you don't need to do anything special to their 
normal HTML tags — with the possible exception of assigning an i d attribute. We strongly recom- 
mend assigning both unique IDs and names to every text-related form control element if your scripts 
will be getting or setting properties, or invoking their methods. IDs are handy for DOM manipula- 
tion and for associating labels with controls, and names are necessary for a form to function normally. 



159 



Part II: JavaScript Tutorial 



When a form is actually submitted to a server-side program, it is the control elements' name attributes 
that are sent to the server along with the elements' values. 

For the visible objects in this category, event handlers are triggered from many user actions, such as 
giving a field focus (getting the text insertion pointer in the field) and changing text (entering new 
text and then leaving the field). Most of your text-field actions are triggered by the change of text (the 
onchange event handler). In current browsers, events fire in response to individual keystrokes as 
well. 

Without a doubt, the single most-used property of a text-related element is the value property. This 
property represents the current contents of the text element. A script can retrieve and set its content at 
any time. Content of the value property is always a string. This may require conversion to numbers 
(see Chapter 8, "Programming Fundamentals, Part I") if text fields are used for entering values for 
math operations. 

Text Object Behavior 

Many scripters look to JavaScript to solve what are perceived as shortcomings or behavioral anomalies 
with text-related objects in forms. We want to single these out early in your scripting experience so that 
they do not confuse you later. 

Most browser forms practice a behavior that was recommended long ago as an informal standard by 
web pioneers. When a form contains only one text i nput object, a press of the Enter/Return key while 
the text object has focus automatically submits the form. For two or more fields in browsers other than 
IE5/Mac and Safari, you need another way to submit the form (for example, a Submit button). This 
one-field submission scheme works well in many cases, such as the search page of most web search 
sites. But if you are experimenting with simple forms containing only one field, you can submit the 
form with a press of the Enter/Return key. Submitting a form that has no other action or target specified 
means the page performs an unconditional reload, wiping out any information entered into the form. 
You can, however, cancel the submission through an onsubmit event handler in the form, as shown 
later in this chapter. You can also script the press of the Enter/Return key in any text field to submit a 
form (see Chapter 32, "Event Objects"). 



To demonstrate how a text field's val ue property can be read and written, Listing 11-2 provides a 
complete HTML page with a single-entry field. When you enter text into the field and press Tab or 
Enter, the input text is made all uppercase. 



LISTING 11-2 



Getting and Setting a Text Object's value Property 

HTML: jsb-ll-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Text Object value Property</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb- 11 -02 . j s "></scri pt> 



160 



Chapter 11 : Forms and Form Elements 



</head> 
<body> 

<hl>Text Object value Property</hl> 
<form i d="UCf orm" acti on = "make-uppercase . php"> 
<P> 

<input type="text" i d="converter" name="converter" val ue="sampl e"> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1102.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

var olnput; // (global) input field to make uppercase 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// apply event handler to the button 

olnput = document . getEl ementBy Id (' converter ') ; 

i f ( olnput ) 

{ 

addEvent(oInput, 'change', upperMe); 

} 

// apply event handler to the form 

var oForm = document . getEl ementBy Id (' UCf orm ') ; 

if (oForm) 

{ 

addEvent(oForm, 'submit', upperMe); 



// make the text UPPERCASE 
function upperMe(evt) 
{ 

// consolidate event handling 
if (!evt) evt = wi ndow . event ; 

// set input field value to the uppercase version of itself 
var sUpperCaseVal ue = ol nput . val ue . toUpperCase ( ) ; 
olnput. value = sUpperCaseVal ue ; 

// cancel default behavior (esp. form submission) 
// W3C DOM method (hide from IE) 

continued 



161 



Part II: JavaScript Tutorial 



LISTING 11-2 



(continued) 



if ( evt . preventDef aul t ) evt . preventDef aul t ( ) ; 



// IE method 
return false; 



Here's how it works: When the page loads into the browser, the i n i t i a 1 i ze ( ) function applies 
event handlers to the form and to the input field it contains. The onchange event handler of both 
the form and the input field invokes the upperMe( ) function, which converts the text to uppercase. 

Notice that the o Input variable, used to refer to the input field converter, is declared outside of 
all the functions and is therefore a global variable. This means that it's accessible from anywhere in 
the script. We've done this so that we can use it from two separate functions — i n i t i a 1 i ze ( ) and 
upperMe( ). (In contrast to global variables, local variables are declared with var inside of a function 
and cannot be seen outside of the function in which they were declared.) 

The core of the upperMe( ) function consists of two statements: 

var sUpperCaseVal ue = ol nput . va 1 ue . toUpperCase ( ) ; 
olnput. value = sUpperCaseVal ue ; 

A lot goes on in the first statement of the function. The right side of the assignment statement 
performs a couple of key tasks. The reference to the val ue property of the object (o Input. val ue) 
evaluates to whatever content is in the text field at that instant. (Remember that olnput is that 
global variable that points to the input field converter.) Then that string is handed over to one of 
JavaScript's string functions, toUpperCase( ), which converts the value to uppercase. The evaluated 
result of the right-side statement is then assigned to the second variable: sUpperCaseVal ue. 
Nothing has changed yet in the text box. That comes in the second statement, where the val ue 
property of the text box is assigned whatever the sUpperCaseVal ue variable holds. We've divided 
this logic into two statements for learning purposes so that you can see the process. In practice, you 
can combine the actions of steps 1 and 2 into one power-packed statement: 

olnput. value = ol nput . va 1 ue . toUpperCase ( ) ; 

The onchange event for the input field is what makes the text uppercase when you press Tab to 
navigate away from that field. Because this is a one-input-field form, the Enter key acts to submit the 
form, so we've set the form's onsubmi t event to run the upperMe( ) function as well. In addition 
to making the text uppercase, that function also cancels the normal submit behavior. (More on event 
capture later in this chapter.) 

If JavaScript is disabled or not supported by the user agent rendering this page, the entered text is 
submitted to a server-side program called make-uppercase, php, which presumably performs the 
uppercasing of the text as well. 

Note 

The function to assign event handlers throughout the code in this chapter and much of the book is 
addEvent( ), a cross-browser event handler explained in detail in Chapter 32, "Event Objects." 

The addEvent( ) function is located in the file jsb global . js on the accompanying CD-ROM and is 
included in each HTML example with a scri pt tag in the document head. ■ 



162 



Chapter 11 : Forms and Form Elements 



The button input object 

We use the button-type input element in many examples in this book. The button is one of the sim- 
plest objects to script. In the simplified object model of this tutorial, the button object has only a few 
properties that are rarely accessed or modified in day-to-day scripts. Like the text object, the visual 
aspects of the button are governed not by HTML or scripts but by the operating system and browser 
that the page visitor uses. By far the most useful event of the button object is the click event. It fires 
whenever the user clicks the button. Simple enough. No magic here. 



The checkbox input object 

A checkbox is also a simple element of the form object, but some of the properties may not be 
entirely intuitive. Unlike the value property of a plain button object (the text of the button label), 
the value property of a checkbox is any other text you want associated with the object. This text 
does not appear on the page in any fashion, but the property (initially set via the value attribute) 
might be important to a script that wants to know more about the purpose of the checkbox within 
the form. 

For example, consider this: 

<input type="checkbox" id="memory" name="remember-me" value="yup"> 
<label for="memory">Remember me on this computer</l abel > 

If we check this checkbox and submit the form, the browser sends the server the name/value pair 
"remember-me" and "yup"; the label text "Remember me on this computer" appears on the screen but 
is not sent to the server. 

The key property of a checkbox object is whether the box is checked. The checked property is a 
Boolean value: true if the box is checked, f al se if not. When you see that a property is a Boolean 
value, it's a clue that the value will be easy to use in an i f or i f . . . el se conditional expression. In 
Listing 11-3, the value of the checked property determines which alert box the user sees. 



LISTING 11-3 



The Checkbox Object's checked Property 

HTML: jsb-ll-03.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Checkbox Inspector</title> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb- 11 -03 . j s "></scri pt> 

</head> 

<body> 

<hl>Checkbox Inspector</hl> 
<form action=""> 
<P> 

<input type="checkbox" i d="checkThi s " name="checkThi s"> 

continued 



163 



Part II: JavaScript Tutorial 



LISTING 11-3 



(continued) 



< 1 a be 1 for="checkThi s">Check here</label> 
<input type="button" i d=" i nspect I t " val ue="Inspect Box"> 
</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1103. js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

var oCheckbox; // checkbox object (global) 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to crucial elements 

oCheckbox = document . getEl ementBy Id (' checkThi s ') ; 
var oButton = document . getEl ementBy Id (' i nspect It ') ; 

// if they exist, apply event handler 

if (oCheckbox && oButton) 

{ 

addEvent ( oButton , 'click', inspectBox); 

) 



// report the checked state of the checkbox 

function inspectBoxO 

{ 

if ( oCheckbox . checked ) 

alert("The box is checked."); 

else 

alert("The box is not checked at the moment."); 



Checkboxes are generally used as preference setters rather than as action inducers. Although a check- 
box object has an onclick event handler, a click of a checkbox should never do anything drastic, 
such as navigate to another page. 



164 



Chapter 11 : Forms and Form Elements 



The radio input object 

Setting up a group of radio objects for scripting requires a bit more work. To let the browser manage 
the highlighting and unhighlighting of a related group of buttons, you must assign the same name 
attribute to each of the buttons in the group. You can have multiple radio groups within a form, but 
each member of the same group must have the same name. 

Assigning the same name to a form element forces the browser to manage the elements differently 
than if they each had a unique name. Instead, the browser maintains an array list of objects with the 
same name. The name assigned to the group becomes the name of the array. Some properties apply 
to the group as a whole; other properties apply to individual buttons within the group and must be 
addressed via array index references. For example, you can find out how many buttons are in a radio 
group by reading the length property of the group: 

formObject . groupName .length 

If you want to find out whether a particular button is currently highlighted via the same checked 
property used for the checkbox, you can access the button element by its position in the collection of 
same-named input fields: 

formObject . groupName[0^\ . checked 

Listing 11-4 demonstrates several aspects of the radio-button object, including how to look through 
a group of buttons to find out which one is checked, and how to use the value attribute and corre- 
sponding property for meaningful work. 

The page includes three radio buttons and a plain button. Each radio button's val ue attribute 
contains the full name of one of the Three Stooges. When the user clicks the button, the oncl i ck 
event handler invokes the ful 1 Name( ) function. In that function, the first statement creates a 
shortcut reference to the form. Next, a for repeat loop looks through all the buttons in the stooges 
radio-button group. An i f construction looks at the checked property of each button. When a 
button is checked, the break statement bails out of the for loop, leaving the value of the i loop 
counter at the number where the loop broke ranks. Then the alert dialog box uses a reference to the 
value property of the i th button so that the full name can be displayed in the alert. 



LISTING 11-4 



Scripting a Group of Radio Objects 

HTML: jsb-ll-04.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Extracti ng Highlighted Radio Button</ti tl e> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb- 11 -04 . j s "></scri pt> 

</head> 

<body> 

<hl>Extracti ng Highlighted Radio Button</hl> 
<form acti on = "stooges . php"> 

continued 



165 



Part II: JavaScript Tutorial 



(continued) 



<f i el dset> 

<1 egend>Sel ect your favorite Stooge : </l egend> 

<P> 

<input type="radio" name="stooges" id="stooges-l" 

value="Moe Howard" checked) 

< 1 a be 1 for="stooges-l">Moe</label> 

</p> 
<P> 

<input type="radio" name="stooges" id="stooges-2" 

value="Larry Fine"> 

<label for="stooges-2">Larry</label> 

</p> 
<P> 

<input type="radio" name="stooges" id="stooges-3" 

value="Curly Howard") 

< 1 a be 1 for="stooges-3">Curly</label> 

</p> 
<P> 

<input type="subtni t" id="Viewer" name="Vi ewer" 
value="View Full Name..."> 

</p> 
</fieldset> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-ll-04.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

var aStooges; // radio button array (global) 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to crucial elements 

var oButton = document . getEl ementBy Id (' Vi ewer ') ; 
var aForms = document . forms ; 

if (aForms) aStooges = a Forms [0] . stooges ; // global variable 

// if they exist, apply event handler 

if (oButton && aStooges) 

{ 

addEvent( oButton , 'click', showFul 1 Name ) ; 

1 



166 



Chapter 11 : Forms and Form Elements 




// display the full name of the selected stooge 

function showFul I Name( ) 

{ 

for (var i = 0; i < aStooges . I ength ; i++) 
{ 

if ( aStooges [ i ]. checked ) 
{ 

break; 



alert("You chose " + aStooges[i ] . v a I ue + "."); 

} 



The select object 

The most complex form control to script is the select element object. As you can see from 
the DOM Level 0 form object hierarchy diagram (see Figure 11-1), the select object is really a 
compound object that contains an array of option objects. Moreover, you can establish this object in 
HTML to display itself as either a drop-down list or a scrolling list — the latter configurable to accept 
multiple selections by users. For the sake of simplicity at this stage, this lesson focuses on deploying 
it as a drop-down list that allows only single selections. 

Some properties belong to the entire select object; others belong to individual options inside the select 
object. If your goal is to determine which item the user selects, and you want the code to work on the 
widest range of browsers, you must use properties of both the select and option objects. 

The most important property of the select object itself is the s el ected I ndex property, accessed as 
follows: 

formObject . sel ectName . selectedlndex 

This value is the index number of the currently selected item. As with most index counting schemes 
in JavaScript, the first item (the one at the top of the list) has an index of zero. The sel ectedlndex 
value is critical for enabling you to access properties of the selected option. Two important properties 
of an option item are text and val ue, accessed as follows: 

formObject . sel ectName . opti ons [n] . text 
formObject . sel ectName . opt i ons [ n] . value 

The text property is the string that appears onscreen in the select object's list. It is unusual for this 
information to be exposed as a form object property because the HTML that generates a select object 
defines the text as an <opti on> tag's nested text. But inside the < opti on > tag, you can set a value 
attribute, which, like the radio buttons shown earlier, enables you to associate some hidden string 
information with each visible entry in the list. 

To read the value or text property of a selected option most efficiently for all browsers, you can 
use the select object's sel ectedlndex property as an index value to the option. References for 
this kind of operation get pretty long, so take the time to understand what's happening here. In 
the following function, the first statement creates a shortcut reference to the select object. Then the 



167 



Part II: JavaScript Tutorial 



selectedlndex property of the select object is substituted for the i ndex value of the opti ons 
array of that same object: 

function inspectO 
{ 

var oList = document . get El ementBy Id( ' choi ces ') ; 
if (oList) 

{ 

var sChosenltemVal ue = oLi st . opti ons [oLi st . sel ectedlndex] . val ue ; 

I 

1 

To bring a select object to life, use the onchange event handler. As soon as a user makes a new 
selection in the list, the script associated with the onchange event is run. Listing 11-5 shows 
a common application for a select object. Its text entries describe places to go in and out of a 
web site, and the val ue attributes hold the URLs for those locations. When a user makes a 
selection in the list, the onchange event handler triggers a script that extracts the val ue property 
of the selected option and assigns that value to the 1 oca ti on . href object property to effect the 
navigation. 

Of course, most of these new locations (web pages) won't already exist on your computer in the folder 
where the HTML page resides. When you select a location and your page attempts to relocate there, 
you'll see a "File not found" error page. Notice the intended page in the address bar, and then click 
the Back button to return to the sample form. 

The form includes a submit button so that, when JavaScript is turned off or is non-existent in the user 
agent, the page still works by submitting the form to a server-side program to perform the redirection. 
Under JavaScript control, it can be argued that this kind of navigation doesn't need a separate Go but- 
ton on the page, and in this example we've hidden the button from view using JavaScript to set its 
display style to "none." Note, however, that some people criticize the usability and accessibility of a 
select list that submits a form as soon as a selection is made. The argument is that since form submis- 
sion isn't a normal function of a select list, adding that behavior with JavaScript will take some users 
by surprise and will switch them to a new page without their deliberate consent. Also, the list's behav- 
ior assumes that the user's first selection from the list is where they really want to go and doesn't allow 
for accidental selections, which anyone could make, but particularly those with motor-skill disabilities. 
Try this form with JavaScript turned off to see the difference for yourself. 



LISTING 11-5 



Navigating with a select Object 

HTML: jsb-ll-05.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Sel ect Navi gati on</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb- 11 -05 . j s "></scri pt> 

</head> 

<body> 



168 



Chapter 11 : Forms and Form Elements 



<hl>Select Navi gati on</hl> 

<form acti on=" redi rect . php" method="get"> 

<P> 

< 1 a be 1 f or="url Li st">Choose a place to go : </l abel > 

<select i d="url Li st" name="url Li st"> 

<option selected val ue="i ndex. html ">Home Page</opti on> 
<option val ue="store . html ">Shop Our Store</opti on> 
<option val ue="pol i ci es . html ">Shi ppi ng Pol i ci es</opti on> 
<option val ue="http : //www . googl e . com">Search the Web</option> 

</sel ect> 

<input type="submi t" id="submit-button" value="Go"> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1105.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

var oList; // select list (global) 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld) 

{ 

// point to crucial elements 

oList = document . getEl ementByld (' url Li st ') ; 

oButton = document . getEl ementById( ' submi t-button ') ; 

// if they exi st . . . 
if (oList && oButton) 
{ 

// make the list dynamic 

addEvent( oLi st , 'change', goThere); 

// make the submit button disappear when JavaScript is running 
oButton . sty 1 e . di spl ay = 'none'; 



// direct the browser to the selected URL 

f uncti on goThere ( ) 

{ 

1 ocati on . href = oLi st . opti ons [oLi st . sel ectedl ndex] . val ue ; 



169 



Part II: JavaScript Tutorial 



Note 

Recent browsers also expose the value property of the selected option item by way of the value property of 
the select object. This is certainly a logical and convenient shortcut, and you can use it safely if your target 
browsers include IE, Mozilla-based browsers, and Safari. ■ 

There is much more to the select object, including the ability to change the contents of a list in newer 
browsers. Chapter 37 covers the select object in depth. 



Passing Elements to Functions with this 

In all the examples so far in this lesson, when an event handler invokes a function that works with 
form elements, the form or form control is explicitly referenced by a global variable. But valuable 
shortcuts exist for transferring information about the form or form control directly to the function 
without having to declare global variables. 

JavaScript features a keyword — this — that always refers to whatever object contains the script in 
which the keyword is used. For instance, if you attach a function to a button by its cl i ck event, then 
you click the button, the keyword this inside the function refers to the button itself. Using this is 
cool: it means having to use fewer global variables, lessening the chance that two independent scripts 
will someday use the same global variable name and mess up each other's logic, and it means that you 
can use the same generic function for multiple elements. Here's a simple example: 

f uncti on i dent i fy ( ) 

{ 

if ( thi s . tagName ) 
{ 

alert('My tagName is ' + thi s . tagName ) ; 

} 

} 

If you apply the i d e n t i f y ( ) function to multiple elements on the page and then click them, each 
reports its tagName: P, LABEL, INPUT, FORM, BODY, etc. 

Take a look at Listing 11-6. There are two functions that use the this keyword: 
pnocessData( ), which is attached to the submit button, and venifySong( ), which is 
attached to the song name input field. 



LISTING 11-6 



Passing Elements to Functions with this 

HTML: jsb-ll-06.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Beatle Pi cker</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 



170 



Chapter 11 : Forms and Form Elements 



<script type="text/ j avascri pt" src=" j sb- 11 -06 . j s "></scri pt> 
</head> 
<body> 

<hl>Beatle Picker</hl> 

<form i d="beatl es -f orm" acti on = "beatl es . php" method="get"> 

<P> 

<1 abel >Choose your favorite Beatl e : </l abel > 



<i nput 


type= 


"radio 


name="Beatl es" 


i d=" radi ol " 












val ue= 


="John Lennon" checked) 








<1 abel 


f or=" 


radi ol 


>John</l abel > 










<i nput 


type= 


"radio 


name="Beatl es" 


i d=" radi o2" 


va" 


ue= 


'Paul McCartney") 


<1 abel 


f or=" 


radi o2 


>Paul </l abel > 










<i nput 


type= 


"radio 


name="Beatl es" 


i d=" radi o3" 


va" 


ue= 


'George Harrison") 


<1 abel 


f or=" 


radi o3 


>George</l abel > 










<i nput 


type= 


"radio 


name="Beatl es" 


i d=" radi o4" 


va" 


ue= 


'Ringo Starr") 


<1 abel 


f or=" 


radi o4 


>Ri ngo</l abel > 











</p> 
<p> 

< 1 abel f or="song")Enter the name of your favorite Beatles song : </l abel > 
<input type="text" id="song" name="song" val ue="El eanor Rigby") 
<input type="submi t" id="submit" val ue="Process Request...") 

</p> 
</ form) 
</body> 
</html > 

JavaScript: jsb-1106.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld ) 

{ 

// point to crucial elements 

var oForm = document . getEl ementByld (' beatl es -form ') ; 

var oSong = document . getEl ementByld (' song ') ; 

var oButtonSubmi t = document . getEl ementByld (' submi t ') ; 

// if they al 1 exi st . . . 

if (oForm && oSong && oButtonSubmi t ) 

{ 

// apply behavior to input field & button 
addEvent ( oSong , 'change', verifySong); 
addEvent(oButtonSubmit, 'click', processData ) ; 

1 

I 

} 

continued 



171 



Part II: JavaScript Tutorial 



LISTING 11-6 



(continued) 



II verify all input & suppress form submission 

function processData ( evt ) 

{ 

// consolidate event handling 
if (!evt) evt = wi ndow . event ; 

// point to the activated control's form ancestor 
var oForm = this. form; 

// see which radio button was selected 

for (var i = 0; i < oForm . Beatl es . 1 ength ; i++) 

{ 

if { oForm . Beatl es [ i ]. checked ) 
! 

break; 

I 

} 

// assign values to variables for convenience 
var sBeatle = oForm . Beatl es [ i ]. val ue ; 
var sSong = oForm. song. val ue; 

// this is where a data lookup would go... 

al ert( "Checki ng whether " + sSong + " features " + sBeatle + 
// cancel form submission 

if ( evt . preventDef aul t ) evt . preventDef aul t ( ) ; 
return false; 



// verify the song name when it's changed 

function verifySongO 

{ 

// get the input song 

// ('this' is the object whose event handler called this function) 
var sSong = thi s . val ue ; 

// this is where a data lookup would go... 

al ert( "Checki ng whether " + sSong + " is a Beatles tune..."); 



The function veri fySong( ) wants access to the value entered into the song input field, so it uses 
this in the statement: 

var sSong = thi s . val ue ; 

In other words, get the value of the current object (the input field) and assign it to the variable 
sSong. We're using this as a shortcut replacement for 



172 



Chapter 11 : Forms and Form Elements 



var olnput = document . getEl ementById( ' song ') ; 
var sSong = olnput . val ue ; 

The function processData( ) needs to refer to several form elements, so it first takes advantage of 
the fact that every form element points to the form it belongs to with the form property: 

var oForm = thi s . f orm; 

Regardless of which input control this refers to, this. form points to the parent form. Then it can 
proceed to use object references such as oForm. Beatl es and oForm. song to point to various con- 
trols within the form by name. 

If you're a bit puzzled by the behavior of this script when you run it in your browser, here's an expla- 
nation of the programming logic behind what you experience. When you enter a new song title in 
the text box and exit the input field by pressing Tab or clicking elsewhere, the onchange event han- 
dler calls the veri fySong( ) function, which displays an alert saying that it's checking the song. (It 
doesn't actually validate it against a database in this example.) 

When you click the Process Request button, its one I i c k event handler calls the function process- 
Da t a ( ) , which announces that it's checking to see if the entered song features the Beatle selected in 
the radio buttons above. 

Now let's throw it two balls at once. Type a new song name in the input field, and then immedi- 
ately click the Process Request button. You see only one alert — the veri fySong ( ) message that 
it's checking the song. Why don't you see both alerts? Because the button click action is interrupted 
by the onchange event handler of the text box. In other words, the button doesn't really get clicked, 
because the onchange alert dialog box comes up first. That's why you have to click the button for 
what seems to be a second time to get the song/Beatle verification. If you don't change the text in 
the field, your click of the button occurs without interruption, and the processData( ) verification 
takes place. 



Note 

Discrepancies between the ways that IE and other browsers handle event assignments and event processing 
require explanations beyond the scope of this tutorial. You'll meet them soon enough, however, beginning in 
Chapter 25, "Document Object Model Essentials," and again in Chapter 32, "Event Objects." ■ 



Submitting and Preyajidating Forms 

In an ordinary HTML document, we submit a form by clicking on a submi t button; the browser then 
gathers up the values we entered or selected with the input controls and sends them to the specified 
URI. JavaScript lets us intercept that submit request, validate the input or do whatever else we need to 
do, and then either permit the form submission to proceed or cancel it so that we can guide the user 
to improve the input. 

You can perform this sort of last-second validation of data or other scripting (for example, 
changing the form's action property based on user choices) in a function invoked by the 
form's onsubmit event handler. We'll go into substantial detail about validation routines in 
Chapter 46, "Data-Entry Validation," on the CD-ROM. For now, we just want to show you how the 
onsubmi t event handler works. 



173 



Part II: JavaScript Tutorial 



To juggle the ways different browsers handle events, we need to use two techniques to cancel 
the event, corresponding exactly to the two techniques our addEvent( ) function uses to apply the 
event handlers in the first place: 

// add an event to an element 
function addEvent(el em, evtType, func) 

{ 

// first try the W3C DOM method 
if (elem.addEventListener) 
{ 

el em . addEvent Li stener ( evtf y pe , func, false); 

} 

// otherwise use the 'traditional' technique 

else 

{ 

elem["on" + evtfype] = func; 

} 

} 

Compare this to how the script in Listing 11-7 cancels the submit event: 

function checkForm( evt ) 

{ 

// consolidate event handling 

if (!evt) evt = window. event; 

// cancel form submission 

// W3C DOM method (hide 

if ( evt . preventDef aul t ) 
// IE method 
return false; 

} 

For browsers compatible with the W3C DOM, the event is added with addEventListener( ), and 
the form submission is cancelled with preventDefaultO. Attempting to invoke a DOM method 
that the browser thinks doesn't exist causes a runtime error, so we protect the older and less capable 
browsers by testing first, to make sure the method exists for the event object. 

For those less capable browsers, notably Internet Explorer, the event is added to the object by setting 
the event property (in this case, onsubmi t), and form submission is cancelled simply by returning a 
false value from the function called by the event handler. 

We'll get into all the whys and wherefores later in this book, but for now let's use this dual technique 
for handling events. 

Listing 11-7 shows a page with a simple validation routine that ensures that all fields have something 
in them before allowing form submission to take place. The HTML marks up a form with four input 
fields and a submit button. Note that the acti on of the form element is the fictitious server-side 
program validate.php. If this page is delivered to a user agent not running JavaScript, the form 
will submit the input values to the server-side program for validation. Fundamental form validation 



from IE) 

evt.preventDefault( ) ; 



174 



Chapter 11 : Forms and Form Elements 



must always happen server-side; we're duplicating that validation in client-side JavaScript to give the 
user a more immediate response to their actions. (Incidentally, that's one indicator of whether there's a 
typo in the script: if you submit this form with any of the input fields blank and the browser window 
attempts to bring up val idate.php, you'll know that you probably made a typo while entering the 
HTML or JavaScript code because the script isn't blocking form submission.) 

After the page loads, the script attaches the checkForm( ) function to the onsubmi t event of the 
form. Note that we're not applying oncl i ck behavior to the submi t button; instead, we're letting 
the button do its normal job and we're intercepting the submission process at the form object itself. 

When submi t is clicked, the next normal step is for the browser to submit the form, but first it hon- 
ors the onsubmi t event handler and calls our function checkForm( ). This function's principal job 
is to loop through all the form controls, looking for a blank input field. If it finds one, it displays an 
error message and cancels form submission. 

Inside the loop, the i f statement performs two tests. The first test is to make sure that we're 
examining form controls whose type properties are text (so as not to bother with, say, buttons). 
Next, it checks to see whether the value of the text field is empty. The && operator (called a Boolean 
AND operator) forces both sides to evaluate to true before the entire condition expression inside the 
parentheses evaluates to true. If either subtest fails, the whole condition fails. 



LISTING 11-7 



Last-Minute Checking Before Form Submission 

HTML: jsb-ll-07.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Form Field Val i dator</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb- 11 -07 . j s "></scri pt> 

</head> 

<body> 

<hl>Form Field Val i dator</hl> 

<form i d="theForm" acti on = "val i date . php" method="get"> 
<p>Please enter all requested i nf ormati on : </p> 
<P> 

< 1 a be 1 f or="f i rstName">Fi rst Name : </l abel > 

<input type="text" i d="f i rstName" name="f i rstName"> 

</p> 
<P> 

< 1 abel for="l astName">Last Name : </l abel > 

<input type="text" id="l astName" name="l astName") 

</p> 
<P> 

< 1 abel f or="age">Age : </l abel > 

<input type="text" id="age" name="age"> 

</p> 

continued 



175 



Part II: JavaScript Tutorial 



(continued) 



<P> 

< 1 a be 1 f or="f avori teCol or">Favori te Col or : </l abel > 

<input type="text" i d="f avori teCol or" name="f avori teCol or"> 

</p> 
<P> 

<input type="submi t" i d="submi t"> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1107.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld ) 

{ 

// point to the form 

var oForm = document . getEl ementByld (' theForm ') ; 

// if it exists, apply the behavior 

if (oForm) 

{ 

addEvent(oForm, 'submit', checkForm); 



// when the form is submitted, 

// check to make sure all input fields have been filled in 

function checkForm(evt) 

{ 

// consolidate event handling 
if (!evt) evt = wi ndow . event ; 

// 'this' is the current object, in this case the form 

for (var i = 0; i < thi s .el ements . 1 ength ; i++) 

{ 

if ( thi s . el ements [ i ]. type == "text" && thi s . el ements [ i ]. val ue == "") 
{ 

al ert( "Fi 1 1 out ALL f iel ds .") ; 

// cancel form submission 

// W3C DOM method (hide from IE) 



176 



Chapter 11 : Forms and Form Elements 



if ( evt . preventDef aul t ) evt . preventDef aul t ( ) ; 
// IE method 
return false; 

I 

) 

// allow form submission 
return true; 

) 



A word about submitO 

The scripted equivalent of submitting a form is the form object's s ubmi t ( ) method. All you need in 
the statement is a reference to the form and this method: 

formObject . submi t( ) ; 

One quirky bit of behavior involving the submi t( ) method and the onsubmit event han- 
dler needs explanation. Although you might think (and logically so, in our opinion) that the 
submit( ) method would be the exact scripted equivalent of the click of the real Submit button, 
it's not. The submi t( ) method does not cause the form's submit event to fire at all. If you want 
to perform validation on a form submitted via the submit( ) method, invoke the validation in the 
script function that ultimately calls the submi t( ) method. 

So much for the basics of forms and form controls. In Chapter 12, you step away from HTML for a 
moment to look at more advanced JavaScript core language items: strings, math, and dates. 



Exercises 



1 . Rework Listings 11-2, 11-3, 11-4, and 11-5 to use the this keyword instead of global vari- 
ables. 

2. For the following form (assume that it's the only form on the page), write at least 10 ways to 
reference the text input field as an object in all modern scriptable browsers. 

<form name="subscription" acti on="cgi -bi n/mai 1 1 i st . pi " method="post"> 

<P> 

<input type="text" id="email" name="emai 1 "> 
<input type="submit"> 

</p> 
</f orm> 

3. Write a function that displays the value of an input field in an alert dialog box, plus the script 
that causes that function to be called when the input field is changed. 

4. A document contains two forms, specifications and accessories. In the acces- 
sories form is a field named a c c 1 . Write at least two different statements that set the con- 
tents of that field to Leather Carrying Case. 

5. Create a page that includes a select object to change the background color of the current page. 
The property that you need to set is document, bo dy.style.backgroundColor, and the 
three values you should offer as options are red, y el 1 ow, and green. In the select list, the 
colors should display as Stop, Caution, and G o . 



177 



Strings, Math, 
and Dates 



CHAPTER 



V 



I 



For most of the lessons in the tutorial so far, the objects at the 
center of attention belong to the document object model (DOM). 
But, as indicated in Chapter 2, "Developing a Scripting Strategy," a 
clear dividing line exists between the DOM and the JavaScript language. The 
language has some of its own objects that are independent of the DOM. These 
objects are defined such that if a vendor wished to implement JavaScript as the 
programming language for an entirely different kind of product, the language 
would still use these core facilities for handling text, advanced math (beyond 
simple arithmetic), and dates. You can find formal specifications of these objects 
in the ECMA-262 recommendation. 



IN THIS CHAPTER 



How to modify strings with 
common string methods 

When and how to use the 
Math object 

How to use the Date object 



Core Language Objects 



It is often difficult for newcomers to programming — or even experienced 
programmers who have not worked with object-oriented languages before — to 
think about objects, especially when objects are attributed to things that don't 
seem to have a physical presence. For example, it doesn't require lengthy 
study to grasp the notion that a button on a page is an object. It has several 
physical properties that make perfect sense. But what about a string of 
characters? As you learn in this chapter, in an object-based environment such 
as JavaScript, "everything that moves" is treated as an object — each piece of 
data from a Boolean value to a date. Each such object probably has one or more 
properties that help define the content; such an object may also have methods 
associated with it to define what the object can do or what you can do to the 
object. 

JavaScript objects that are not part of the DOM are called core language objects. 
You can see the full complement of them in the Quick Reference in Appendix A. 
This chapter focuses on the Stri ng, Math, and Date objects. 



179 



Part II: JavaScript Tutorial 



String Objects 

You have used St r i ng objects many times in earlier lessons. A string is any text inside a quote pair. 
A quote pair consists of either double quotes (" ") or single quotes (' '). That JavaScript includes 
two types of quotes makes it easy to nest one string inside another. In the following example, the 
al ert ( ) method requires a quoted string as a parameter: 

alert('You cannot lose.'); 

If the quoted expression includes an apostrophe, it's easy enough to switch the outer quotes to double: 

alert("You can't lose."); 

When the solution isn't so simple, as when both apostrophe and quotation mark appear in the quoted 
string, escape sequences come to the rescue. More on them in Chapter 15, "The String Object." 

JavaScript imposes no practical limit on the number of characters that a string can hold. However, 
most older browsers have a limit of 255 characters for a script statement. This limit is sometimes 
exceeded when a script includes a lengthy string that is to become scripted content in a page. You 
need to divide such lines into smaller chunks, using techniques described in a moment. 

You have two ways to assign a string value to a variable. The simplest is a basic assignment statement: 
var my String = "Howdy"; 

This works perfectly well except in some exceedingly rare instances. You can also create a string object 
using the more formal syntax that involves the new keyword and a constructor function (that is, it 
constructs a new object): 

var my String = new St ri ng (" Howdy ") ; 

Whichever way you initialize a variable with a string, the variable receiving the assignment can 
respond to all St r i ng object methods. 

Joining strings 

Bringing two strings together as a single string is called concatenation, a term you learned in Chapter 
8, "Programming Fundamentals, Part I." String concatenation requires one of two JavaScript operators. 
Even in your first close look at script, in Chapter 3, "Selecting and Using Your Tools," you saw how 
the addition operator (+) combines multiple strings into one: 

var today = new Date ( ) ; 

var msg = "This is JavaScript saying it's now " + today. 
toLocal eStri ng( ) ; 

As valuable as the + operator is, another related operator can be even more scripter-friendly: +=. This 
operator is helpful when you are assembling large strings in a single variable. The strings may be so 
long or cumbersome that you need to divide the building process into multiple statements. Or you 
might decide to split the concatenation into several statements to help it make more sense to the 
human reader. The pieces may be combinations of string literals (strings inside quotes) and variable 
values. The clumsy way to do it (perfectly doable in JavaScript) is to use the addition operator to 
append more text to the existing chunk: 



180 



Chapter 12: Strings, Math, and Dates 



var msg = " Four score" ; 
msg = msg + " and seven " ; 
msg = msg + " years ago,"; 

But the += operator, called the add-by-value operator, offers a handy shortcut. The symbol for the 
operator is a plus and equal sign together. This operator means append the stuff on the right oj me to 
the end of the stuff on the left of me. Therefore, the preceding sequence is shortened as follows: 

var msg = " Four score" ; 
msg += " and seven " ; 
msg += " years ago, " ; 

You can also combine the operators if the need arises: 

var msg = " Four score" ; 

msg += " and seven" + " years ago"; 

String methods 

Of all the core JavaScript objects, the String object has the most diverse collection of methods asso- 
ciated with it. Many methods are designed to help scripts extract segments of a string. Another group, 
rarely used and now obsolete in favor of Cascading Style Sheets (CSS), wraps a string with one of 
several style-oriented tags (a scripted equivalent of tags for font size, font style, and the like). 

In a string method, the string being acted upon becomes part of the reference followed by the method 
name: 

myStri ng .met hod Name ( ) ; 

All methods return a value of some kind. Most of the time, the returned value is a converted version 
of the string object referred to in the method call — but the original string is still intact. To capture 
the modified version, you need to assign the results of the method to a variable: 

var result = mySt r i ng . methodName ( ) ; 

The following sections introduce you to several important string methods available to all browser 
brands and versions. 

Changing string case 

Two methods convert a string to all uppercase or all lowercase letters: 

var result = string. toUpperCaseC ) ; 
var result = string. toLowerCaseC ) ; 

As always, you must strictly observe the case of each letter of the method names if you want them to 
work. These methods come in handy when your scripts need to compare strings that may not have the 
same case (for example, a string in a lookup table compared with a string typed by a user). Because 
the methods don't change the original strings attached to the expressions, you can simply compare the 
evaluated results of the methods: 

var foundMatch = false; 

if ( st ri ngA . toUpperCase ( ) == stri ngB . toUpperCase( ) ) 
{ 

foundMatch = true; 

} 



181 



Part II: JavaScript Tutorial 



String searches 

You can use the string.indexOfO method to determine whether one string is contained by 
another. For example, say you've built a contact form on a web site that sends visitors' messages 
to the public relations department, but you want to carbon copy the ombudsman any messages 
containing the word "complaint." That word could occur anywhere within the long message string. In 
this case, you probably don't need to know exactly where the word occurs, just whether it's there. 

The string.indexOfO method returns a number indicating the index value (zero-based) of the 
character in the larger string where the smaller string begins. The key point about this method is that, 
if no match occurs, the returned value is - 1 . To find out whether the smaller string is inside, all you 
need to test is whether the returned value is something other than - 1 . 

Two strings are involved with this method: the shorter one and the longer one. The longer string is 
the one that appears in the reference to the left of the method name; the shorter string is inserted as a 
parameter to the i ndexOf ( ) method. To demonstrate the method in action, the following fragment 
looks to see whether the input message contains the word 'complaint': 

var sMsg = ' ' ; 

var olnput = document . get El ementBy Id (' message ') ; 
if (olnput) 

sMsg = olnput . val ue ; 

var isComplaint = false; 

if ( sMsg . i ndexOf ( "compl ai nt" ) != -1) 

isComplaint = true; 

The operator in the i f construction's condition ( ! =) is the inequality operator. You can read it as 
meaning is not equal to. 

Extracting copies of characters and substrings 

To extract a single character at a known position within a string, use the charAt( ) method. The 
parameter of the method is an index number (zero-based) of the character to extract. When we say 
extract, we don't mean delete, but grab a snapshot of the character. The original string is not modified 
in any way. 

For example, consider a script in a mam window that is capable of inspecting a variable, stri ngA, 
in another window that displays map images of different corporate buildings. When the window has a 
map of Building C in it, the s t r i n g A variable contains "Building C " . In English the building let- 
ter is always at the 10th character position of the string (or number 9 in a zero-based counting world), 
so the script can examine that one character to identify the map currently in that other window: 

var stri ngA = "Building C"; 
var bldgLetter = st ri ngA . cha rAt ( 9 ) ; 
// result: bldgLetter = "C" 

There are two similar methods — string.substr( ) and string.substringO — that enable 
you to extract a contiguous sequence of characters, provided that you know the starting position of 
the substring you want to grab. The difference between the two methods is that string.substr( ) 



182 



Chapter 12: Strings, Math, and Dates 



wants to know the length of the substring, whereas string.substring( ) wants to know the end- 
ing position of the substring: 

st ri ng . subs t r ( s ta rti ngPos i ti on [, length]) 
stning.substring(startingPosition [, endingPosition]) 

Either method will extract everything up to the end of the original string if the second parameter 
(length or ending position) is omitted. The original string from which the extraction is made appears 
to the left of the method name in the reference. The starting and ending position parameters are index 
values (zero-based). 



van stningA = "banana daiquiri"; 



van excenpt = st ri ngA . subst n ( 2 , 4 ) ; // result: "nana" 

van excenpt = st ri ngA . subst n ( 2 ) ; // result: "nana daiquiri" 

var excerpt = stri ngA . substni ng ( 2 , 6 ) ; // result: "nana" 

van excenpt = stri ngA . substni ng ( 2 ) ; // result: "nana daiquiri" 

String manipulation in JavaScript is fairly cumbersome compared with that in some other scripting 
languages. Higher-level notions of words, sentences, or paragraphs are absent. Therefore, sometimes 
it takes a bit of scripting with string methods to accomplish what seems like a simple goal. Yet you 
can put your knowledge of expression evaluation to the test as you assemble expressions that utilize 
heavily nested constructions. 

For example, let's say you want to grab everything from a multiword expression except the first word: 

var stringA = "The Painted Bird"; 
var firstSpace = stri ngA. i ndexOf( " "); 
van excenpt = stri ngA . substni ng ( fi rstSpace + 1); 
// result: excerpt = "Painted Bird" 

Assuming that the first word can be of any length, the second statement uses the string, 
i ndexOf ( ) method to look for the first space character. We add 1 to that value to serve as the 
starting index value for the s t ri ng . s ubs t r i ng ( ) method. We omit the second 1 ength parameter 
in order to extract everything up to the end of stri ngA. 

Creating statements like this one is not something you are likely to enjoy over and over again, so in 
Chapter 23, "Function Objects and Custom Objects," we show you how to create your own library of 
string functions that you can reuse in all of your scripts that need their string-handling facilities. More 
powerful string-matching facilities are also built into today's browsers by way of regular expressions (see 
Chapter 15, "The String Object," and Chapter 45, "The Regular Expression and RegExp Objects"). 



The Math Object 

JavaScript provides ample facilities for math — far more than most scripters who don't have a back- 
ground in computer science and math will likely use. But every genuine programming language needs 
these powers to accommodate clever programmers who can make windows fly in circles onscreen. 

The Math object contains all these powers. This object is unlike most of the other objects in JavaScript 
in that you don't generate copies of the object to use. Instead, your scripts use the properties and 



183 



Part II: JavaScript Tutorial 



methods of a single Math object. (Technically, one Math object actually occurs per window or frame, 
but this fact has no impact whatsoever on your scripts.) Programmers call this kind of fixed object 
a static object. That Math object (with an uppercase M) is part of the reference to the property or 
method. Properties of the Math object are constant values, such as pi and the square root of 2: 

var pi Val ue = Math . PI ; 

var rootOfTwo = Math . SQRT2 ; 

Math object methods cover a wide range of trigonometric functions and other math functions that 
work on numeric values already defined in your script. For example, you can find which of two num- 
bers is the larger: 

var larger = Math.max( valuel, value2); 
Or you can raise one number to a power of 10: 

var result = Math . pow( va 1 uel , 10); 
More common, perhaps, is the method that rounds a value to the nearest integer value: 

var result = Math . round ( va luel ) ; 

Another common request of the Math object is a random number. The Math . random( ) method 
returns a floating-point number between 0 and 1. If you design a script to act like a card game, you 
need random integers between 1 and 52; for dice, the range is 1 to 6 per die. To generate a random 
integer between 0 and any top value, use the following formula 

Math . fl oor( Math . random( ) * (n + 1)) 

where n is the top number. (Math. floor returns the integer part — the digits to the left of the dec- 
imal point — of any floating-point number.) To generate random numbers between 1 and any higher 
number, use this formula 

Math . f 1 oor(Math . random( ) * n) + 1 
where n equals the top number of the range. For the dice game, the formula for each die is 

newDieValue = Math . f 1 oor(Math . random( ) * 6) + 1; 

To see this, enter the right part of the preceding statement in the top text box of The Evaluator Jr. and 
repeatedly click the Evaluate button. 

The Date Object 

Working with dates beyond simple tasks can be difficult business in JavaScript. A lot of the difficulty 
comes from the fact that dates and times are calculated internally according to Greenwich Mean Time 
(GMT) — provided that the visitor's own internal PC clock and control panel are set accurately. As 
a result of this complexity, better left for Chapter 17, "The Date Object," this section of the tutorial 
touches on only the basics of the JavaScript Date object. 



184 



Chapter 12: Strings, Math, and Dates 



A scriptable browser contains one global Date object (in truth, one Date object per window) that is 
always present, ready to be called upon at any moment. The Date object is another one of those static 
objects. When you wish to work with a date, such as displaying today's date, you need to invoke the 
Date object constructor function to obtain an instance of a Date object tied to a specific time and 
date. For example, when you invoke the constructor without any parameters, as in 

va r today = new Date ( ) ; 

the Date object takes a snapshot of the PC's internal clock and returns a Date object for that instant. 
Notice the distinction between the static Date object and a Date object instance, which contains an 
actual date value. The variable today contains not a ticking clock but a value that you can examine, 
tear apart, and reassemble as needed for your script. 

Internally, the value of a Date object instance is the time, in milliseconds, from zero o'clock on Jan- 
uary 1, 1970, in the GMT zone — the world standard reference point for all time conversions. That's 
how a Date object contains both date and time information. 

You can also grab a snapshot of the Date object for a particular date and time in the past or future 
by specifying that information as parameters to the Date object constructor function: 



va r 


someDate = 


new 


va r 


someDate = 


new 


va r 


someDate = 


new 


va r 


someDate = 


new 


va r 


someDate = 


new 



:h dd , yyyy ) ; 
, mm , dd , hh , mm , ss ) 



If you attempt to view the contents of a raw Date object, JavaScript converts the value to the local 
time-zone string, as indicated by your PC's control panel setting. To see this in action, use The Evalu- 
ator Jr.'s top text box to enter the following: 



new Date ( ) ; 

Your PC's clock supplies the current date and time as the clock calculates them (even though 
JavaScript still stores the date object's millisecond count in the GMT zone). You can, however, 
extract components of the Date object via a series of methods that you apply to a Date object 
instance. Table 12-1 shows an abbreviated listing of these properties and information about their 
values. 



Caution 

Be careful about values whose ranges start with zero, especially the months. The getMonth( ) and 
setMonth( ) method values are zero based, so the numbers are 1 less than the month numbers you are 
accustomed to working with (for example, January is 0 and December is 11). ■ 



You may notice one difference about the methods that set values of a Date object. Rather than return- 
ing some new value, these methods actually modify the value of the instance of the Date object refer- 
enced in the call to the method. 



185 



Part II: JavaScript Tutorial 



TABLE 12-1 



Some Date Object Methods 


Method 




Value Range 


Description 


dateObj . 


getTime( ) 


0-. . . 


Milliseconds since 1/1/70 00:00:00 GMT 


dateObj. 


getYear( ) 


70-. . . 


Specified year minus 1900; four-digit year for 2000+ 


dateObj. 


getFul 1 Year( ) 


1970-.. . 


Four-digit year (Y2K-compliant); version 4+ browsers 


dateObj. 


getMonth ( ) 


0-11 


Month within the year (January = 0) 


dateObj. 


getDate( ) 


1-31 


Date within the month 


dateObj. 


getDay( ) 


0-6 


Day of week (Sunday = 0) 


dateObj. 


getHours ( ) 


0-23 


Hour of the day in 24-hour time 


dateObj. 


getMi nutes ( ) 


0-59 


Minute of the specified hour 


dateObj. 


getSeconds ( ) 


0-59 


Second within the specified minute 


dateObj. 


setTi me ( va 1 ) 


0-. . . 


Milliseconds since 1/1/70 00:00:00 GMT 


dateObj. 


setYea r (val) 


70-. . . 


Specified year minus 1900; four-digit year for 2000+ 


dateObj. 


setMonth (val ) 


0-11 


Month within the year Qanuary = 0) 


dateObj. 


setDate (val ) 


1-31 


Date within the month 


dateObj. 


setDay (va 1 ) 


0-6 


Day of week (Sunday = 0) 


dateObj. 


setHours (val ) 


0-23 


Hour of the day in 24-hour time 


dateObj. 


setMi nutes (val ) 


0-59 


Minute of the specified hour 


dateObj. 


setSeconds (val ) 


0-59 


Second within the specified minute 



Date Calculations 

Performing calculations with dates frequently requires working with the millisecond values of the 
Date objects. This is the surest way to compare, add, and subtract date values. To demonstrate a few 
Date object machinations, Listing 12-1 displays the current date and time and one way to calculate 
the date and time seven days from now. 



LISTING 12-1 



Date Object Calculations 

HTML: jsb-12-01.html 

<!D0CTYPE html> 
<html > 
<head> 



186 



Chapter 12: Strings, Math, and Dates 



<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Date Calculation</title> 

<script type=" text/javascript" src="../jsb-global . js"X/script> 
<script type=" text/javascript" src="jsb-12-01.js"X/script> 

</head> 

<body> 

<hl>Date Cal cul ati on</hl> 

<form i d="date-f orm" acti on="date-cal c . php"> 

<P> 

<label for="today ">Today is:</label> 

<input type="text" id = "today" name="today" size="80"> 

</p> 
<P> 

<label for="nextWeek">Next week will be:</label> 

<input type="text" i d="nextweek" name="nextweek" size="80"> 

</p> 
<P> 

<input type="submi t" id="submit"> 

</p> 
</f orm> 
</body> 
</html > 



JavaScript: jsb-12-01.js 

// run script when the page has loaded 
addEvent(window, 'load', calcDates); 

// calculate dates and plug into document 
function calcDates() 

{ 

var dTodaysDate = new DateO; 
// plug in today 

var oToday = document . getEl ementById( ' today ') ; 
if (ofoday) 

{ 

oToday. value = dfodaysDate; 

) 



/ / plug in next week 

var oNextWeek = document . get El ementBy Id (' nextWeek ') ; 
if (oNextweek) 

( 

// today in milliseconds 

var msToday = df oday sDate . getTi me ( ) ; 

// one week = 1000 milliseconds * 60 seconds * 60 minutes 

// * 24 hours * 7 days 

var msOneWeek = 1000 * 60 * 60 * 24 * 7; 

continued 



187 



Part II: JavaScript Tutorial 



LISTING 12-1 



(continued) 



II next week in milliseconds 

var msNextWeek = msToday + msOneWeek; 

// next week as date object 

var dAWeekFromNow = new Date(msNextWeek) 



// plug in string value 
oNextWeek . val ue = dAWeekFromNow; 



The script first creates a new Date object and assigns it to the variable dTodaysDate. Then it dis- 
plays the current date and time by setting the value of the input field today equal to dTodaysDate. 
Although you might expect that this would insert a copy of the Date object into the input field, what 
really happens is that it uses the toStri ng( ) method of the Date object to output a string such as 

Sun Dec 05 2010 16:47:20 GMT-0800 (Pacific Standard Time) 

Next, we display the date and time one week from now. To work with milliseconds, we start by 
assigning the current date and time in milliseconds to variable msToday. To add one week to this, 
we need to know how many milliseconds there are in a week: 1000 ms. per second, 60 seconds per 
minute, 60 minutes per hour, 24 hours per day, and seven days per week. The product of all these 
we store in variable msOneWeek. We add that week of milliseconds to the current date and time, and 
then use the result to create a new Date object, which we store in variable dAWeekFromNow. Dis- 
playing the resultant date and time is done the same way as before — simply by assigning the new 
Date object to an input field's val ue attribute. 

To add time intervals to or subtract time intervals from a Date object, you can use a shortcut that 
doesn't require the millisecond conversions. By combining the date object's set and get methods, 
you can let the Date object work out the details. For example, in Listing 12-1, you could replace the 
"next week" logic with: 

dTodaysDate . setDate ( dTodaysDate . getDate ( ) + 7); 
oNextWeek . va 1 ue = dTodaysDate; 

Because JavaScript tracks the date and time internally as milliseconds, the accurate date appears in the 
end, even if the new date is into the next month. JavaScript automatically takes care of figuring out 
how many days there are in a month, as well as in leap years. 

Many other-quirks and complicated behavior await you if you script dates in your page. As later 
chapters demonstrate, however, the results may be worth the effort. 



188 



Chapter 12: Strings, Math, and Dates 



Exercises 



1 . Create a web page that has one form field for entering the user's email address, and a Submit 
button. In the accompanying JavaScript script, write a presubmission validation routine that 
verifies that the text field contains the @ symbol used in all email addresses before you allow 
submission of the form. 

2. Given the string " Internet Expl orer", fill in the blanks of the stri ng . substri ng 
( ) method parameters here that yield the results shown to the right of each method call. 

var myString = "Internet Explorer"; 

myString.substring( ) // result ="Int" 

myString.substring( ) // result = "plorer" 

myStri ng . substri ng( ) // result = "net Exp" 

3. Consider this logic for extracting the part of a string that comes after the first word: 

var stringA = "The Painted Bird"; 

var firstSpace = stri ngA. i ndexOf ( " "); 

var excerpt = stri ngA. substri ng( fi rstSpace + 1); 

What will happen in this logic if s t r i n g A does not contain a space? Work out what you think 
should occur, then run the script to see if you're right. 

4. Fill in the rest of the function in the listing that follows so that it looks through every character 
of the entry field and counts how many times the letter e (either upper- or lowercase) appears 
in the field. (Hint: All that is missing is a for repeat loop.) 

var inputString = 'Elephantine'; 
var count = 0; 

MISSING CODE 

var msg = "The number of e's in '" + thi s . ma i nst ri ng . val ue + "'"; 
msg += " is " + count; 
al ert(msg) ; 

5. Create a page that has two fields and one button. The button should trigger a function that 
generates two random numbers between I and 6, placing each number in one of the fields. 
(Think of using this page as a substitute for rolling a pair of dice in a board game.) 

6. Create a script that displays the number of days between today and next Christmas. 



189 



Scripting Frames 

and Multiple Windows 




One of the attractive aspects of JavaScript for some applications on the 
client is that it allows user actions in one frame or window to influ- 
ence what happens in other frames and windows. In this section of the 
tutorial, you extend your existing knowledge of object references to the realm of 
multiple frames and windows. 



Frames: Parents and Children 

You've seen in earlier top-level hierarchy illustrations (such as Figure 6-2) that 
the wi ndow object is at the top of the chart. The wi ndow object also has several 
synonyms, which stand in for the wi ndow object in special cases. For instance, 
in Chapter 10, "Window and Document Objects," you learned that self is 
synonymous with wi ndow when the reference applies to the same window 
that contains the script's document. In this lesson, you learn the roles of three 
other references that point to objects behaving as windows: frame, top, 
and parent. 

Loading an ordinary HTML document into the browser creates a model in the 
browser that starts out with one wi ndow object and the document it contains. 
The top rungs of the hierarchy model are as simple as can be, as shown in 
Figure 13-1. This is where references begin with wi ndow or sel f (or with 
document because the current window is assumed). 



IN THIS CHAPTER 



Relationships among frames in 
the browser window 

How to access objects and 
values in other frames 

How to control navigation of 
multiple frames 

Communication skills between 
separate windows 



191 



Part II: JavaScript Tutorial 



FIGURE 13-1 



Single-frame window and document hierarchy, 
window 



document 



To frame or not to frame? 

Frames and iFrames are valid HTML and their use might be seen as desirable for accomplishing some 
tasks. However, frame-based web sites pose serious usability and accessibility issues that can make 
them less than ideal for general web site development. 

The fundamental problem with framesets is that any given combination of framed pages is not directly 
addressable. That is, if you navigate through a frameset to bring up a particular combination of content 
in the frames, the URL in the browser's address bar will remain that of the parent frameset document, 
not that of the actual content you're viewing. This lack of unique addressing of frame-paged content 
prevents search engines from indexing content and prevents other people from publishing links to the 
framed content, bookmarking them on their computers, or sharing them in email. Framesets can also be 
disorienting or completely inaccessible for the users of mobile devices and assistive technology such as 
magnifiers and screen-readers. 

Web usability expert Jakob Nielsen wrote "Why Frames Suck (Most of the Time)" back in 1996. The 
situation hasn't improved in all the years since. 

Alternatives to frames that avoid these problems include using server-side scripting to combine multiple 
source pages, and using the CSS properties overflow: auto, to create fields of scrolling content, and 
pos i ti on : f i xed, to establish sections that don't move when the rest of the page scrolls. 

In this book, we assume that you've considered the pros and cons of using frames and may have a 
web development problem — or mere curiosity — that requires their use. We want you to know how 
to manipulate them with JavaScript if you have to, and they make for great exercise in navigating the 
DOM, but we don't recommend their use in most circumstances. 



The instant a framesetting document loads into a browser, the browser starts building a slightly dif- 
ferent hierarchy model. The precise structure of that model depends entirely on the structure of the 
frameset defined in that framesetting document. Consider the following skeletal frameset definition: 

< ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset// EN " 
"http: //www.w3 .org/TR/html4/frameset.dtd"> 

<html > 
<head> 

<meta http-equi v="Content-Type" content="text/html ; charset=utf-8"> 
<title>Title of all pages in this f rameset</ti tl e> 
</head> 

<frameset col s="50%,50%"> 

<frame name="l eftFrame" src="somedocl . html " ti tl e=" Frame 1"> 
<frame name=" ri ghtFrame" src="somedoc2.html " ti tl e=" Frame 2"> 
<nof rames> 



192 



Chapter 13: Scripting Frames and Multiple Windows 



</nof ranies) 
</f rameset) 
</html> 

This markup splits the browser window into two frames side by side, with a different document 
loaded into each frame. The model conveys both the structure (parent with children) and the layout 
(the relative sizes of the frames and whether they're set up in columns or rows). Because frames 
markup is not backward-compatible — it displays absolutely nothing in browsers that don't support 
frames — we also provide a no-frames alternative, which might be actual content or a hyperlink to a 
frameless page. 

Framesets establish relationships among the frames in the collection. Borrowing terminology from the 
object-oriented programming world, the framesetting document loads into a parent window. Each of 
the frames defined in that parent window document is a child frame. Figure 13-2 shows the hierarchi- 
cal model of a two-frame environment. This illustration reveals a lot of subtleties about the relation- 
ships among framesets and their frames. 



FIGURE 13-2 



Two-frame window and document hierarchy. 



top or parent 
<frameset> 



child 
<frame> 




child 

<frame> 










document 




document 



It is often difficult at first to visualize the frameset as a window object in the hierarchy. After all, with 
the exception of the URL showing in the browser's Location/Address field, you don't see anything 
about the frameset in the browser. But that window object exists in the object model. Notice, too, 
that in the diagram the framesetting parent window has no document object showing. This may also 
seem odd, because the window obviously requires an HTML file containing the specifications for the 
frameset. In truth, the parent window has a document object associated with it, but it is omitted 
from the diagram to better portray the relationships among parent and child windows. A frameset par- 
ent's document cannot itself contain most of the typical HTML objects such as forms and controls, so 
references to the parent's document are rarely, if ever, used. 

If you add a script to the framesetting document that needs to access a property or method of that 
window object, references are like any single-frame situation. Think about the point of view of a script 
located in that window. Its immediate universe is the very same window. 

Things get more interesting when you start looking at the child frames. Each of these frames contains 
a document object whose content you see in the browser window, and the structure is such that each 
frame's document is entirely independent of the other. It is as though each document lived in its own 
browser window. Indeed, that's why each child frame is also a window type of object. A frame has the 
same kinds of properties and methods as the wi ndow object that occupies the entire browser. 



193 



Part II: JavaScript Tutorial 



From the point of view of either child window in Figure 13-2, its immediate container is the pa rent 
window. When a parent window is at the top of the hierarchical model loaded in the browser, that 
window is also referred to as the top object. 

References Among Family Members 

Given the frame structure of Figure 13-2, it's time to look at how a script in any one of those win- 
dows can access objects, functions, or variables in the others. An important point to remember about 
this facility is that if a script has access to an object, function, or global variable in its own window, 
that same item can be reached by a script from another frame in the hierarchy (provided that both 
documents come from the same web server). 

A script reference may need to take one of three possible routes in the two-generation hierarchy 
described so far: parent to child; child to parent; or child to child. Each of the paths between these 
windows requires a different reference style. 

Parent-to-child references 

Probably the least common direction taken by references is when a script in the parent document 
needs to access some element of one of its frames. Since the parent can contain one or more frames, 
the parent maintains an array of the child frame objects. You can address a frame by array syntax or 
by the name you assign to it with the id or name attribute inside the <f rame> tag. In the follow- 
ing examples of reference syntax, we substitute a placeholder named ObjFuncVarName for whatever 
object, function, or global variable you intend to access in the distant window or frame. Remember 
that each visible frame contains a document object, which generally is the container of elements you 
script; be sure that references to the elements include document. With that in mind, a reference from 
a parent to one of its child frames can follow any one of these models: 

[window.]frames[n]. ObjFuncVarName 

[wi ndow . ] frames [ " frameName" ] . Obj FuncVarName 

[wi ndow. ] frameName . Obj FuncVarName 

Numeric index values for frames are based on the order in which their <f rame> tags appear in the 
framesetting document. You will make your life easier, however, if you assign recognizable names to 
each frame and use the frame's name in the reference. 

Child-to-parent references 

It is not uncommon to link scripts to the parent frameset document (in the head portion) that multi- 
ple child frames or multiple documents in a frame use as a common script library. Because they load 
in the frameset, these scripts load only once while the frameset is visible. If other documents from the 
same server load into the frames over time, they can take advantage of the parent's scripts without 
having to load their own copies into the browser. 

From the child's point of view, the next level up the hierarchy is called the parent. Therefore, a 
reference from a child frame to items at the parent level is simply: 

parent . Obj FuncVarName 

If the item accessed in the parent is a function that returns a value, the returned value transcends the 
parent/child borders down to the child without hesitation. 

var sValue = pa rent . FuncNamei ) ; 



194 



Chapter 13: Scripting Frames and Multiple Windows 



When the parent window is also at the top of the object hierarchy currently loaded into the browser, 
you can optionally refer to it as the top window, as in: 

top . ObjFuncVarName 

Using the top reference can be hazardous if for some reason your web page gets displayed in some 
other web site's frameset. What if your top window is not the master frameset's top window? There- 
fore, we recommend using the parent reference whenever possible (unless you want your script to 
fail when nested inside an unwanted framer of your web site). 

Child-to-child references 

The browser needs a bit more assistance when it comes to getting a child window to communicate 
with one of its siblings. One of the properties of any window or frame is its parent (whose value is 
null for a single window). A reference must use the parent property to work its way out of the cur- 
rent frame to a point that both child frames have in common — the parent, in this case. When the 
reference is at the parent level, the rest of the reference can carry on as though it were starting at the 
parent. Thus, from one child to one of its siblings, you can use any of the following reference formats: 

parent. framesfn] . ObjFuncVarName 

parent. frames[" frameName" ] . ObjFuncVarName 

parent . frameName . ObjFuncVarName 

A reference from the other sibling back to the first looks the same, but the frames [ ] array index 
or frameName part of the reference differs. Of course, much more complex frame hierarchies exist 
in HTML. Even so, the object model and referencing scheme provide a solution for the most deeply 
nested and gnarled frame arrangement you can think of — following the same precepts you just 
learned. 

Frame-Scripting Tips 

One of the first mistakes that frame-scripting newcomers make is writing immediate script statements 
that call on other frames while the pages load. The problem here is that you cannot rely on the doc- 
ument loading sequence to follow the frameset source-code order. All you know for sure is that the 
parent document begins loading first. Regardless of the order of <f rame> tags, child frames can begin 
loading in any sequence. Moreover, a frame's loading time depends on other elements in the docu- 
ment, such as images or Java applets. 

Fortunately, you can use a certain technique to initiate a script when all the documents in the frame- 
set are completely loaded. Just as the load event for a window fires when that window's document 
is fully loaded, a parent's load event fires after the load events in its child frames have fired. When 
you specify awindow.onload event handler in a script linked to the frameset document, it's the 
equivalent of applying the event handler to the frameset element. That handler might invoke a 
function in the framesetting document that then has the freedom to tap the objects, functions, or 
variables of all frames throughout the object hierarchy. 

Make special note that a reference to a frame as a type of window object is quite separate from a 
reference to the frame element object. An element object is one of those DOM element nodes in the 
document node tree (see Chapter 6, "Browser and Document Objects"). The properties and methods 
of this node differ from the properties and methods that accrue to a window-type object. It may 
be a difficult distinction to grasp, but it's an important one. The way you reference a frame — as a 
window object or element node — determines which set of properties and methods are available to 
your scripts. 



195 



Part II: JavaScript Tutorial 



Cross-Reference 

See Chapter 26, "Generic HTML Element Objects," for a more detailed introduction to element node 
scripting. ■ 

If you start with a reference to the frame element object, you can still reach a reference to the 
document object loaded into that frame, but the syntax is different, depending on the browser. IE44- 
and Safari let you use the same document reference as for a window; Mozilla-based browsers follow 
the W3C DOM standard more closely, using the contentDocument property of the frame element. 
To accommodate both syntaxes, you can build a reference as follows: 

va r docOb j ; 

var frameObj = document . getEl ementByldC "myFrame" ) ; 
if ( frameObj . contentDocument ) 
{ 

docObj = frameOb j . contentDocument ; 

} 

else 
{ 

docObj = frameOb j . document ; 

} 

About iframe Elements 



The i frame element is supported as a scrip table object in IE4+, Mozilla-based browsers, and Safari 
(among other modem browsers). It is often used as a way to fetch and load HTML from a server with- 
out disturbing the current HTML page. It's not uncommon for an i frame to be hidden from view 
while scripts handle all the processing between it and the main document. (Today, the trick of asyn- 
chronously loading data from the server into an already-downloaded page is often accomplished using 
XMLHttpRequest( ) — see Chapter 39, "Ajax, E4X, and XML," on the CD.) 

An i frame element becomes another member of the current window's frames collection, 

but you may also reference the i frame as an element object through W3C DOM document 

. getEl ementByldO terminology. As with the distinction between the traditional frame-as-window 

object and DOM element object, a script reference to the document object within an i frame 

element object needs special handling. See Chapter 27, "Window and Frame Objects," for additional 

details. 

Highlighting Footnotes: A Frameset 

Scripting Example 

For a taste of inter-window scripting, consider a frameset that highlights a footnote in one frame when 
the corresponding link is clicked in the document text. Figure 13-3 shows what this frameset looks 
like, and Listing 13-1 provides the markup and scripting. 

The three HTML files establish a frameset with two child frames, one for the main text and one for the 
footnotes. Clicking on a footnote link in the text brings the selected footnote to the top of the footnote 
frame. It does this by adding the element ID of the selected footnote to the 'hash' of the URL: 

<a target="f rameFootnotes " <J 

href="jsb-13-01-fra me -footnotes. html #footnote -01 "> Footnote K/a> 



196 



Chapter 13: Scripting Frames and Multiple Windows 



FIGURE 13-3 



Highlighting Footnotes frameset. 



i Highlighting Footnotes - MoziMa Hrefox 



Efi» E* It"'™ History frickmarts loots ttetp 



Highlighting Footnotes - The Text 



Fa more detail p*rw Wfl F.nytW<r J 



Done 



Footnotes 



Vlvmnn coofBC: NuILm ranseqod 

" hum i *k jqih u.ir in rrjTFnfvh 

aed, uukrundft et. wiu. \1 jf raazs mm: 
■itfrdniia. ttulis «<r 1^t3li 

llkil-^i- :i \:\hi.f-rMv M| iJ-i-i-- 

eti, i*n Nui i rf tortus IX"tcv turn 
burin nJ sizar Actum nwli In av-Li.pjr 
cocr- alb esai In y hai nn bsiln i^c 
trnupThi nunrci, Erwpn teAs scdouqiH' 

m jgim_ °. t! n ■■ BnjKicict rWMi. - pirTm y g c 

into Eti«ii ifimu pxui. -vKlibutura id 
(iii s*i ac aer ■. air; n jugur 

. rln-^jnr Mninr- lr,|T[-.ir "Ijlfflji 

E'topichI i* mrt turpu- 'i b& njirmn 
bfanAtidiii buip^mfeM n mc Ut 

vdmi 

Qcoe-: ok brus due arx-?rs tacn 
wcidsqn ailifiita. b^epjejd pa" comibui 

IIKTtlA. [ifi Hk'tf^S h IUeiL]CL-= VllLl 

Utortw vt hmt4 If* -5*4 fWfed 
iiirrdiaii arilf Mawn vdiiifiuvi «• 
■iauiniBj.tnclirf l.il^n'Jkni Sedmirfus 
n'j^iii. defim j. scckriMjuc vtac 
mlrrduni ic uluh CiaaJoLwrih od» 



.- 



The ta rget attribute identifies the child frame while the href specifies which document will appear 
in that frame. The final part of the href URL #footnote-01 matches up with the footnote markup: 

<1 1 id="footnote-01">Lorem ipsum dolor ... 

It is basic browser functionality that, when the ID of an element is set as the hash of a URL, the page 
scrolls up (if it can) to position that element at the top of the window. 

JavaScript and CSS work together to highlight the selected footnote: when the user clicks on a foot- 
note link in the text window, JavaScript assigns a "selected" class to the footnote element. CSS styles 
that class with a background color. 



LISTING 13-1 



Highlighting Footnotes 

HTML: jsb-13-01-frameset.html 

<!D0CTYPE HTML PUBLIC " -//W3C//DTD HTML 4.01 Frameset // EN " 

" http : //www .w3.org/TR/html4/frameset.dtd"> 
<html > 

<head> 

continued 



197 



Part II: JavaScript Tutorial 



(continued) 



<meta http-equi v="Content-Type" content="text/html ; charset=utf -8"> 
<title>Highlighting Footnotes</title> 
< 1 ink href="jsb-13-01-frameset.css" rel=" stylesheet" 
type=" text /ess " medi a = " al 1 " > 
</head> 

<frameset cols="66%,33%"> 

<frame name="f rameText" s rc=" j sb-13-01 -frame-text . html " title="Frame 1"> 
<frame name=" frame Footnotes" src="jsb-13-01-frame -footnotes. html " 

title="Frame 2"> 
<nof rames> 
<body> 

<hl>Text with Footnotes</hl> 

<p>Proceed to <a href=" jsb-13-01-f rame-text-f ootnotes . html "> 
combined text and f ootnotes</a> . </p> 

</body> 
</nof rames> 
</f rameset> 
</html > 

Styl esheet : jsb- 13 01 -frameset . ess 

/* limit the width of the page */ 
html 

{ 

width: 60 em; 
max-width: 100%; 

) 



HTML: jsb-13-01-frame-text.html 

<!D0CTYPE html PUBLIC " -//W3C//DTD HTML 4.01 Trans i ti onal // EN " 

" http : //www .w3.org/TR/html4/loose.dtd"> 
<html > 

<head> 

<meta http-equi v="Content-Type" content="text/html ; charset=utf -8"> 
<ti tl e>Hi ghl i ghti ng Footnotes - The Text</title> 
<script type=" text/javascript" src="../jsb-global .js"X/script> 
<script type=" text /Java script" src="jsb-13-01-frame-text.js"X/script> 

</head> 

<body> 

< h 1 > H i ghl i ghti ng Footnotes - The Text</hl> 

<p>For details please see <a target="f rameFootnotes" 

h re f="j sb-13-01 - frame -footnotes, html #f ootnote-01 "> Footnote K/aX/p> 

<p>For more details please see <a target="f rameFootnotes" 

h re f="j sb-13-01 -frame -footnotes. html #footnote-02"> Footnote 2</aX/p> 



198 



Chapter 13: Scripting Frames and Multiple Windows 



<p>For even more details please see <a target="f rameFootnotes" 

h re f =" j sb- 13-01 -frame -footnotes. html #f ootnote-03"> Footnote 3</aX/p> 

</body> 
</html > 

JavaScript: j sb - 13 - 01 - frame- text. js 

// run script when the page has loaded 
add Event (wi ndow , 'load', initialize); 

// global memory of the last footnote highlighted 
var oFootnote = null; 
var s Footnoted ass = ''; 

// apply behaviors when document has loaded 
function i n i t i a 1 i z e ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . get El ementBy Id ) 

{ 

// collect anchors 

var aAnchors = document . get El ementsByf agName (' a ') ; 
// for each anchor . . . 

for (var i = 0; i < aAnchors . 1 ength ; i++) 

( 

// get the target of the link 

var sfarget = aAnchors [i ]. getAttri bute( ' target ') ; 

// if there is a target and it's the footnotes frame 
if (sfarget && sTarget == ' f rameFootnotes ' ) 

{ 

addEvent ( aAnchors [ i ] , 'click', hi ghl i ghtFootnote ) ; 

I 

1 

} 

} 

// highlight the selected footnote 
function hi ghl i ghtFootnote( ) 

{ 

// restore previously highlighted footnote (if any) 
if (oFootnote) 

( 

oFootnote . cl assName = sFootnoteCl ass ; 

} 

// get the HREF of the clicked anchor 
var sHref = thi s . getAttri bute (' href ') ; 

continued 



199 



Part II: JavaScript Tutorial 



LISTING 13-1 



(continued) 



II get the 'hash' of the URL 
var iHash = sHref .indexOf ( '#' ) ; 
// everything after the hash mark is 
var sFootnoteld = sH ref . subs tr ( i Hash 



the element Id 
+ 1); 



// the target of the link is the frame Id 
var sFrameld = thi s . getAttri bute( ' target ' \ 

II if the frame exists... 
if (parent[sFrameId]) 



// point to 

oFootnote = 

// if it exists 
if (oFootnote) 



the indicated footnote 

parent[sFra me Id] . document. get El erne nt By Id ( sFootnoteld) 



// remember its original class to restore it later 
s Footnoted ass = oFootnote . cl assName ; 



// set its new class 
oFootnote . cl assName = 



sel ected ' 



} 

HTML: jsb- 13 -01 -frame -footnotes . html 

<!D0CTYPE html PUBLIC " -//W3C//DTD HTML 4.01 Trans i ti onal // EN " 

" http : //www .w3.org/TR/html4/loose.dtd"> 
<html > 

<head> 

<meta http-equi v="Content-Type" content="text/html ; charset=utf -8"> 
<title> Footnotes </title> 

<link href="jsb-13-01-fra me -footnotes. ess" rel="stylesheet" 
type=" text /ess " medi a=" al 1 " > 
</head> 
<body> 

<hl>Footnotes</hl> 



<ol cl ass="footnotes"> 

<li i d=" f ootnote-01 " >Lorem ipsum dolor sit amet, consectetuer 
adipiscing el it. Suspendisse vulputate fells ut est. Vivamus congue. 
Nullam consequat. Etiam elit ipsum, pulvinar in, commodo sed, malesuada 
et, wisi. Maecenas nunc odio, interdum et, mollis eget, egestas quis, enim. 
Vestibulum augue leo, molestie ut, sollicitudin sit amet, ultricies eu, diam. 
Nam vel metus. Donee non ligula at augue dictum mollis. In tristique convallis 
erat. In pharetra, ligula vitae fringilla ultrices, turpis tellus scelerisque 
magna, vitae imperdiet nibh quam nec justo. Etiam diam purus, vestibulum id, 



200 



Chapter 13: Scripting Frames and Multiple Windows 



placerat nec, varius et, augue. Maecenas vitae nulla et est iaculis scelerisque. 
Mauris tempus sagittis ligula. Nunc consectetuer sem vitae nisi. Praesent sit 
amet turpis. Sed rutrum blandit tellus. Suspendisse in enim. Ut vel mi.</li> 

<li i d="footnote-02">Donec nec lacus. Class aptent taciti sociosqu ad 
litora torquent per conubia nostra, per inceptos hymenaeos. Nulla lobortis 
vehicula leo. Sed eleifend interdum ante. Mauris vel magna ac diam imperdiet 
bibendum. Sed metus ipsum, dictum a, scelerisque vitae, interdum ac, massa. 
Cras lobortis odio at augue. Aenean fermentum bibendum purus. Ut congue 
interdum turpis. Ut quis mi a ligula viverra hendrerit. Nulla facilisi. 
Nullam lacinia, ligula ac congue feugiat, risus diam fringilla tellus, 
condimentum volutpat eros risus sit amet dolor. </li> 

<li i d="footnote-03">Proi n et urna. Morbi in odio. In mauris tellus, 
tincidunt vitae, ultrices a, sollicitudin sit amet, nulla. Praesent consequat, 
lectus auctor imperdiet dapibus, risus turpis feugiat orci , sit amet tempus quam 
erat a purus. Nullam neque nulla, fringilla ut, dictum id, luctus placerat, 
urna. Sed vel vel it. Fusee eget erat a quam auctor pulvinar. Phasellus vel 
neque eu risus feugiat sagittis. Nulla est. Duis sed massa. Duis ac leo quis 
sapien fringilla posuere. Nam facilisis lorem. Nullam bibendum, wisi quis 
ultrices bibendum, sem pede volutpat sem, ut ultrices odio nisi ut ligula. 
Cras ligula est, tempus et, tempus vitae, pretium eget, ipsum. Integer 
Blandit mattis wisi. Curabitur eget tellus at neque vulputate dignissim. 
Phasellus leo nibh, euismod ac, congue vel, interdum et, turpis. Fusee 
viverra aliquet wisi.</li> 
</ol> 
</body> 
</html > 



Styl esheet : jsb- 13 01 -frame -footnotes .ess 

/* style the selected footnote */ 
ol. footnotes li. selected 

{ 

background-color: aqua; 

1 



Let's walk through the JavaScript to see how the highlighting works. The script is linked to the 
frame-text, html document because it's the act of clicking the links in that document that triggers 
the highlighting event. The addEvent( ) function call tells JavaScript to run the i n i t i a 1 i z e ( ) 
function when the document has loaded. That function loops through all the anchor elements in the 
document. If it finds a target attribute set to f rameFootnotes, it applies the oncl ick event to 
run the function hi ghl i ghtFootnote( ). 

When the user clicks on one of these links in the document text, the highlightFootnoteO func- 
tion gives the anchor element the sel ected class. To make it easy to restore a link to its previous 
class name later, the script stores the current anchor element pointer and its class attribute in global 
variables oFootnote and sFootnoteClass. So, the first thing it does when a link is clicked is to 
restore the previously-clicked link, if any. 



201 



Part II: JavaScript Tutorial 



To set the class attribute of the footnote in the other child frame, the script needs to determine the 
names of the frame and the footnote element. The frame name is exactly the same as the target 
attribute of the link that's clicked. The footnote element is whatever element in the footnote frame has 
the ID equal to the hash at the end of the link's URL. 

If the named frame exists and the named element exists, the script can safely save the element's 
existing class (if any) and set the class to selected. Finally, the style sheet linked to the footnotes 
document applies a background color to any footnote with the sel ected class. 

There are two important scripting principles illustrated with Listing 13-1. First, the fundamental 
operation of this page — bringing the selected footnote to the top of the footnote frame — is handled 
entirely by HTML without any help from JavaScript. This ensures that the page will be usable when 
viewed with user agents that don't support JavaScript, such as mobile devices, or with browsers 
in which the user has disabled JavaScript. This is an example of progressive enhancement, which 
stipulates that our scripting efforts should enhance already functional pages rather than supplying 
mission-critical functionality. We want to improve the experience for those who are running JavaScript 
and not break the page for those who aren't. 

Second, we're using JavaScript to indicate that the footnotes are "selected" but not how they should be 
styled. We could have scripted: 

oFootnote . styl e . backgroundCol or = 'aqua'; 

Instead, the styling is left to CSS. This is an example of separation of development layers, whereby 
HTML structure and content are kept separate from JavaScript behavior and CSS presentation. This 
mode of development makes it quick and easy to create new code, tweak existing code, and apply old 
code to new projects. For example, when the web site designer changes the look of the site — and 
rest assured nearly every site will be changed either during development or afterward — cosmetic 
changes should be within the grasp of someone who knows CSS, without requiring the services of 
a JavaScript programmer. 

References for Multiple Windows 

In Chapter 10 you saw how to create a new window and communicate with it by way of the wi ndow 
object reference returned from the wi ndow . open ( ) method. In this section, we show you how one 
of those subwmdows can communicate with objects, functions, and variables in the window or frame 
that creates the subwindow. 

Every wi ndow object has a property called opener. This property contains a reference to the win- 
dow or frame that held the script whose window.open( ) statement generated the subwindow. For 
the main browser window and frames therein, this value is null. Because the opener property is a 
valid window reference (when its value is not nul 1 ), you can use it to begin the reference to items in 
the original window — just like a script in a child frame uses parent to access items in the parent 
document. (The parent keyword isn't used for a subwindow's opener, however.) 

Listing 13-2 contains two documents that work together in separate windows, j sb- 1 3 - 02 -ma i n 
.html displays a button that opens a smaller window and loads jsb-13-02-sub.html into it, and 
another button that closes the subwindow. The main window document also contains a text field that 
gets filled in when you enter text in a corresponding field in the subwindow. 



202 



Chapter 13: Scripting Frames and Multiple Windows 



Note 

You may have to turn off pop-up blocking temporarily to experiment with these examples. 

Because so many people have set their browsers to block pop-up windows, and because pop-ups can be so 
disorienting to folks using assistive technology such as screen readers, and simply irritating to everyone else, we 
don't recommend that you create subwindows with JavaScript in real-world applications — and especially not 
for any critical function. Instead, use other techniques, such as CSS pop-ups, that gracefully degrade to simple 
HTML navigation in the absence of styling and scripting. ■ 

In the main window's script, the openSubWi ndow( ) function generates the new window. Because 
the closeSubWindowO function needs to know which window to close, we store the pointer to the 
new window in a global variable. 



LISTING 13-2 



A Main Window Document 

HTML: jsb-13-02-main.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Opener</title> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 

<script type=" text /javascript" src="jsb-13-02-main.js"X/script> 
</head> 
<body> 

<hl>Opener</hl> 

<form action=""> 
<P> 

<input type="button" value="Open Sub Window" i d="open -sub-wi ndow"> 
<input type="button" value="Close Sub Window" i d = " c 1 ose-sub-wi ndow"> 

</p> 
<P> 

<label>Text incoming from subwi ndow : </l abel > 
<input type="text" id="output"> 

</p> 
</ form) 
</body> 
</html > 

JavaScript: jsb-1302main.js 

// run script when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

// global pointer to sub-window 
var oSubWindow; 

continued 



203 



Part II: JavaScript Tutorial 



LISTING 13-2 



(continued) 



II apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to button 

var oButton = document . getEl ementBy Id (' open -sub-wi ndow ' ) 

// if it exists, apply behavior 

if (oButton) 

{ 

addEvent( oButton , 'click', openSubWindow) ; 



// point to button 

oButton = document . getEl ementBy Id( ' cl ose-sub-wi ndow ') ; 

// if it exists, apply behavior 

if (oButton) 

{ 

addEvent( oButton , 'click', cl oseSubWi ndow) ; 



// open (create) sub window 
function openSubWi ndow( ) 
{ 

// store sub-window pointer in global variable 

oSubWindow = wi ndow . open ( "j sb- 13-02-sub . html " , "sub", "hei ght=200 ,wi dth=300" 



// close (destroy) sub window 

function cl oseSubWi ndow( ) 
{ 

// if the sub-window has been opened, close it 

if (oSubWindow) 

{ 

oSubWi ndow . cl ose ( ) ; 



HTML: jsb-13-02-sub.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Sub-Document</ti tl e> 

<script type=" text /javascript" src=". ./jsb-global .js"X/script> 



204 



Chapter 13: Scripting Frames and Multiple Windows 



<script type=" text /javascript" src="jsb-13-02-sub.js"></ script) 
</head> 
<body> 

<hl>Sub-Document</hl> 

<form i d="sendForm" action=""> 
<P> 

< T a be I for="i nput">Enter text to be copied to the main wi ndow : </l abel > 
<input type="text" id="input"> 

</p> 
<P> 

<input type="button" value="Send Text to Opener" i d="send-text"> 
</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1302- sub.js 

// run script when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

// apply behaviors when document has loaded 

f uncti on i ni ti al i ze ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to button 

var oButton = document . getEl ementBy Id (' send-text ') ; 

// if it exists, apply behavior 

if (oButton) 

{ 

addEvent ( oButton , 'click', copyToOpener ) ; 

} 



// copy input text to output in parent 

function copyToOpener ( ) 

! 

// find the input field in the current window 
var olnput = document . getEl ementBy Id (' i nput ') ; 

// find the output field in the parent window 

var oOutput = opener . document . getEl ementBy Id (' output ') ; 

// if they both exist, copy input text 

if (olnput && oOutput) 

{ 

oOutput . val ue = olnput. val ue; 

1 

1 



205 



Part II: JavaScript Tutorial 



All the action in the subwindow document stems from the o n c 1 i c k event handler assigned to the 
Send Text button. It triggers the copyToOpene r ( ) function, which assigns the subwindow input 
field's value to the value of the output field in the opener window's document. Remember, the con- 
tents of each window and frame belong to a document. Even after your reference targets a specific 
window or frame, the reference must continue helping the browser find the ultimate destination, 
which generally is some element of the document. 

Just one more lesson to go before we let you explore all the details elsewhere in the book. We'll use 
the final tutorial chapter to show you some fun things you can do with your web pages, such as 
changing images when the user rolls the mouse over a picture. 



Exercises 

Before answering the first three questions, study the structure of the following frameset for a web site 
that lists college courses: 

<html > 
<head> 

</head> 

<frameset rows="85%, 15%"> 

<frameset col s="20% ,80%"> 

<frame name="mechani cs " src="hi storylOlM. html "> 
<frame name="descri pti on" s rc = " hi story 101 D . html "> 

</f rameset> 

<frameset cols="100%"> 

<frame name="navi gati on" s rc=" navi gator . html " > 

</f rameset) 
</f rameset> 
<nof rames> 

</nof rames> 
</html > 

1 . Each document that loads into the description frame links to a JavaScript script that uses the 
onload event handler to store a course identifier value in the framesetting document's global 
variable currCourse. Write the function that sets this value to historylOl. 

2. Draw a block diagram that describes the hierarchy of the windows and frames represented in 
the frameset definition. 

3. Write the HTML markup and JavaScript statements located in the navigation frame that 
together perform two actions: load the file french201M.html into the mechanics frame, and 
load the file french201D.html into the description frame. 

4. While a frameset is still loading, a JavaScript error message suddenly appears, saying, "win- 
dow.document.navigation.form. selector is undefined." What do you think is happening in the 
application's scripts, and how can you solve the problem? 

5. A script in a child frame of the main window uses window.open( ) to generate a second 
window. How can a script in the second window access the location object (URL) of the 
top (framesetting) window in the main browser window? 



206 



Images and Dynamic 
HTML 




The previous eight lessons have been intensive, covering a lot of 
ground for both programming concepts and JavaScript. Now it's 
time to apply those fundamentals to learning more advanced tech- 
niques. We cover two areas here. First, we show you how to implement 
the ever-popular mouse rollover, in which images swap when the user 
rolls the cursor around the screen. Then we introduce you to techniques 
for modifying a page's style and content after the page has loaded. 

Although image swapping on mouse rollover can be accomplished more easily 
using Cascading Style Sheets (CSS), we'll demonstrate how to do it with 
JavaScript because you'll probably see a lot of it in legacy scripts, and because 
it's a handy way to illustrate how to manipulate image objects. 



The Image Object 



One of the objects contained by the document is the Image object — 
supported in all scriptable browsers since the days of NN3 and IE4. Image object 
references for a document are stored in the object model as an array belonging 
to the document object. Therefore, you can reference an image by array index 
or image name. Moreover, the array index can be a string version of the image's 
name. All the following are valid references to an image object: 

document. get El erne nt By Id ( " i mageName" ) 

document.getElementsByTagName("7'mg")[n] 

document . i mages [ n~\ 

document . i mages [ " i mageName" ] 

document. i mageName 

(The last reference will work only if i mageName doesn't include any valid 
HTML ID characters that aren't permitted in JavaScript names, such as a hyphen 
or period.) 

We are no longer constrained by ancient scriptable browser limitations that 
required an image be encased within an a element to receive mouse events. You 



IN THIS CHAPTER 



How to pre-cache images 

How to swap images 
for mouse rollovers 

Changing style sheet settings 

Modifying body content 
dynamically 



207 



Part II: JavaScript Tutorial 



may still want to do so if a click is intended to navigate to a new URL, but to use a visitor's mouse 
click to trigger local JavaScript execution, it's better to let the img element's event handlers do all 
the work. 

Interchangeable images 

The advantage of having a scriptable image object is that a script can change the image occupying the 
rectangular space already occupied by an image. In current browsers, the images can even change size, 
with surrounding content automatically reflowing around the resized image. 

The script behind this kind of image change is simple enough. All it entails is assigning a new URL to 
the i mg element object's s re property. The size of the image on the page is governed by the hei ght 
and width attributes set in the <img> tag, and the height and width properties set in the style 
sheet. The most common image rollovers use the same size of image for each of the rollover states. 

Pre-caching images 

Images take extra time to download from a web server until they are stored in the browser's cache. If 
you design your page so that an image changes in response to user action, you usually want the same 
fast response that users are accustomed to in other programs. Making the user wait seconds for an 
image to change can detract from enjoyment of the page. 

JavaScript comes to the rescue by enabling scripts to load images into the browser's memory cache 
without displaying the image, a technique called pre-caching images. The tactic that works best is to 
preload the image into the browser's image cache while the page initially loads. Users are less impa- 
tient for those few extra seconds when the main page loads, than they are waiting for an image to 
download in response to some mouse action. However, keep in mind that there is a balance. Today's 
audience tends to give a page less than 10 seconds to load before moving on. Although pre-caching 
images means a fast response to a mouse action, if you pre-cache too many images, you risk losing 
web site visitors before they can see your amazing image swapping in response to mouse actions. 

Pre-caching an image requires constructing an image object in memory. An image object created in 
memory differs in some respects from the document img element object that you create with the 
<img> tag. Memory-only objects are created by script, and you don't see them on the page at all. 
But their presence in the document code forces the browser to load the images as the page loads. 
The object model provides an Image object constructor function to create the memory type of image 
object as follows: 

var mylmage = new ImageC width, height); 

Parameters to the constructor function are the pixel width and height of the image. These dimen- 
sions should match the width and height attributes of the < i mg > tag. Once the image object exists 
in memory, you can then assign a filename or URL to the sre property of that image object: 

mylmage. sre = "sotneArt.gif"; 

When the browser encounters a statement assigning a URL to an image object's sre property, the 
browser fetches and loads that image into the image cache. All the user sees is some extra loading 
information in the status bar, as though another image were in the page. By the time the entire page 
loads, all images generated in this manner are tucked away in the image cache. You can then assign 
your cached image's sre property, or the actual image URL, to the sre property of the document 
image created with the <img> tag: 

document . i mages [0] . s re = mylmage. sre; 



208 



Chapter 14: Images and Dynamic HTML 



or 

document . get El ementBy Id ( "my Img "). s rc = mylmage.src ; 
The change to the image in the document is instantaneous. 

Listing 14-1 demonstrates a page that has one <img> tag and a select list that enables you to replace 
the image in the document with any of four pre-cached images (including the original image specified 
for the tag). If you type this listing, you can obtain copies of the four image files from the companion 
CD-ROM in the Chapter 14 directory of listings. (You still must type the HTML and code, however.) 



LISTING 14-1 



Pre-Caching Images 

HTML: jsb-14-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e> Image Object</ti tl e> 
<style type="text/css"> 

i mg 

{ 

height:90px; wi dth : 120px ; 



<script type=" text /javascript" src="../jsb-global .js"X/script> 

<script type="text/ j avascri pt" src="j sb- 14-01 . j s "></scri pt> 
</head> 
<body > 

<h2>Image 0bject</h2> 

<img src="deskl . gi f " i d="thumbnai 1 "> 

<f orm> 

<select id="imageChooser"> 

<option value="imagel">Bands</ option) 
<option value="image2">Clips</option> 
<option value="image3">Lamp</option> 
<option value="image4">Erasers</ option) 
</sel ect> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-14-01.js 

// initialize when the page has loaded 
var olmageChooser ; 

addEvent(wi ndow, "load", initialize); 

continued 



209 



Part II: JavaScript Tutorial 



LISTING 14-1 



(continued) 



f uncti on i ni ti al i ze ( ) 



// get W3C DOM or IE4+ reference for an ID 
// i mageChooser is the select element 
f ( document . getEl ementBy Id ) 

olmageChooser = document . getEl ementBy Id( " i mageChooser " ) 

el se 

olmageChooser = document . imageChooser ; 



addEvent( olmageChooser , 'change', loadCached); 



// initialize empty array 
var imageLibrary = new Array( 
// pre-cache four images 



imageLi brary [ 
imageLi brary [ 
imageLi brary [ 
imageLi brary [ 
imageLi brary [ 
imageLi brary [ 
imageLi brary [ 
imageLi brary [ 



i magel 
imagel 
image2 
image2 
image3 
image3 
image4 
i mage4 



'] = new 
'] . src = 
'] = new 
'] .src = 
'] = new 
'] . src = 
'] = new 
'] .src = 



Image(120,90) 
"deskl . gi f " ; 
Image(120,90) 
"desk2 . gi f " ; 
Image(120,90) 
"desk3 . gi f " ; 
Image(120,90) 
"desk4 . gi f " ; 



// load an image chosen from select list 
function loadCachedO 



var imgChoice = olmageChooser . opti ons [olmageChooser . sel ectedl ndex] . val ue ; 
document .getEl ementBy Id ( "thumbnail").src = imageLibrary [imgChoice]. src; 



As the page loads, it executes several statements immediately. These statements create an array that is 
populated with four new memory image objects. Each image object has a filename assigned to its src 
property. These images are loaded into the image cache as the page loads. Down in the body portion 
of the document, an < i mg> tag stakes its turf on the page and loads one of the images as a starting 
image. 

A select element lists user-friendly names for the pictures while housing (in the option values) the 
names of image objects already pre-cached in memory. When the user makes a selection from the 
list, the loadCachedO function extracts the selected item's value — which is a string index of the 
image within the imageLi brary array. The src property of the chosen image object is assigned to 
the src property of the visible img element object on the page, and the pre-cached image appears 
instantaneously. 



210 



Chapter 14: Images and Dynamic HTML 



Creating image rollovers 

A favorite technique to add some pseudo-excitement to a page is to swap button images as the user 
rolls the cursor over them. The degree of change to the image is largely a matter of taste. The effect 
can be subtle (a slight highlight or glow around the edge of the original image) or drastic (a radical 
change of color). Whatever your approach, the scripting is the same. 

When several of these graphical buttons occur in a group, we tend to organize the memory image 
objects as arrays, and create naming and numbering schemes that facilitate working with the arrays. 
Listing 14-2 shows such an arrangement for four buttons that control a slide show. The code in the 
listing is confined to the image-swapping portion of the application. This is the most complex and 
lengthiest listing of the tutorial, so it requires a bit of explanation as it goes along. It begins with a 
style sheet rule for each of the i mg elements located macontroller container. 



LISTING 14-2 



Image Rollovers 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html 
<ti tl e>Sl i de Show/Image Rol 1 overs</ti tl e> 
<style type="text/css"> 
di v#control 1 er i mg { 

height: 70px; width: 136px; padding: 5px; 

} 

</styl e> 

<script type="text/ j avascri pt" src=" . . /jsb-gl obal . 
<script type="text/javascript"> 



; charset=utf -8"> 



j s "></scri pt> 



Only browsers capable of handling image objects should execute statements that pre-cache images. 
Therefore, the entire sequence is nested inside an i f construction that tests for the presence of the 
document, images array. In older browsers, the condition evaluates to undefined, which an i f con- 
dition treats as fal se: 

if ( document . i mages ) 
{ 

Image pre-caching starts by building two arrays of image objects. One array stores informa- 
tion about the images depicting the graphical buttons' off position; the other is for images 
depicting their on position. These arrays use strings (instead of integers) as index values. The 
string names correspond to the names given to the visible img element objects whose tags 
come later in the source code. The code is clearer to read (for example, you know that the 
offImgArray["fi rst" ] entry has to do with the First button image). Also, as you see later in this 
listing, rollover images don't conflict with other visible images on the page (a possibility if you rely 
exclusively on numeric index values when referring to the visible images for the swapping). 

After creating the array and assigning new blank image objects to the first four elements of the array, 
we go through the array again, this time assigning file pathnames to the src property of each object 



211 



Part II: JavaScript Tutorial 



stored in the array. These lines of code execute as the page loads, forcing the images to load into the 
image cache along the way: 

// pre-cache all 'off button images 
var of f ImgArray = new ArrayO; 
off ImgArray["f i rst"] = new Image( 136 , 70 ) ; 
off ImgArray["pnev"] = new Image(136,70) ; 
off ImgArray ["next"] = new Image( 136,70) ; 
off ImgAr ray [ " 1 ast"] = new Image(136,70) ; 

II off image array set 'off image path for each button 
off ImgArray["f i rst"] . src = "firstoff .png"; 
off ImgArray["prev"] .src = "prevof f . png" ; 
off ImgArray["next"] .src = "nextoff .png" ; 
of f ImgArray [" 1 ast" ]. src = "1 astoff .png" ; 

// pre-cache all 'on' button images 
var onlmgArray = new Array(); 
onImgArray["fi rst"] = new Image( 136,70) ; 
onImgArray["prev"] = new Image( 136 , 70 ) ; 
onImgArray["next"] = new Image( 136 , 70 ) ; 
onImgArray["l ast"] = new Image( 136 , 70 ) ; 

// on image array set 'on' image path for each button 
on ImgArray [ "fi rst" ]. src = "f i rston . png" ; 
onImgArray["prev"] .src = "prevon.png" ; 
onImgArray["next"] .src = "nexton . png" ; 
onImgArray["l ast"] .src = " 1 aston . png" ; 



Do you see the repeating pattern in the statements above? Instead of those statements, here's a way 
you could take advantage of the repeating pattern: 

var offlmgArray = new ArrayO; 
var onlmgArray = new ArrayO; 

var ButtonArray = ["first", "prev", "next", "last"]; 

for (var i=0; i < ButtonArray . 1 ength ; i++) 

{ 

var Button = ButtonArray [ i ] ; 



// pre-cache 'off button image 

off ImgArray [Button] = new Image ( 136 , 70 ) ; 

of f ImgArray [Button ]. s rc = Button + "off. png"; 



// pre-cache 'on' button image 
onImgArray[Button] = new Image ( 136 , 70 ) ; 
onImgArray[Button] . src = Button + "on. png"; 



As you can see in the following code, when the user rolls the mouse atop any of the visible 
document image objects, the onmouseover event handler invokes the imageOn( ) function, 



212 



Chapter 14: Images and Dynamic HTML 



passing the name of the particular image. The i mageOn ( ) function uses that name to synchronize 
the document, i mages array entry (the visible image) with the entry of the in-memory array of 
on images from the onlmgArray array. The src property of the array entry is assigned to the 
corresponding document image src property. At the same time, the cursor changes to look like it 
does over active links. 

// functions that swap images & status bar 

function imageOn(imgName) 

I 

if (document. images) 
I 

document . imagesfimgName] . styl e . cursor = "pointer"; 
document . images[imgName] . src = onlmgArrayfimgName] . src ; 

I 

} 

The same goes for the onmouseout event handler, which needs to turn the image off by 
invoking the imageOff ( ) function with the same index value. 

function imageOff ( imgName) 
I 

if ( document . images ) 
{ 

document . imagesfimgName] . styl e . cursor = "default"; 
document . imagesfimgName] . src = off ImgArraytimgName] .src; 



Both the onmouseover and onmouseout event handlers set the status bar text to a friendly 
descriptor — at least in those browsers that still support displaying custom text in the status bar. The 
onmouseout event handler sets the status bar message to an empty string. 

function setMsg(msg) 
{ 

wi ndow . status = msg; 
return true; 

} 

For this demonstration, we disable the functions that control the slide show. But we leave the empty 
function definitions here so they catch the calls made by the clicks of the links associated with the 
images. 

// controller functions (disabled) 
function goFi rst( ) 



function goPrevt ) 



function goNextO 



213 



Part II: JavaScript Tutorial 



function goLastt ) 



// event handler assignments 

function initO 

{ 

if (document. getEl ementByld) 
{ 

olmageFi rst = document . getEl ementById( "fi rst" ) ; 
olmagePrev = document . getEl ementByldt "prev" ) ; 
olmageNext = document. getEl ementById( "next" ) ; 
olmageLast = document . getEl ementById( "1 ast" ) ; 

} 

el se 
{ 

olmageFirst = document . fi rst ; 
olmagePrev = document . prev ; 
olmageNext = document . next ; 
olmageLast = document . 1 ast ; 



addEvent(oImageFi rst, 'click', goFirst); 
addEventtoImageFi rst, 'mouseover', function() 
( 

imageOn( "fi rst" ) ; 

return setMsgC'Go to first picture"); 

1); 

addEvent(oImageFi rst, 'mouseout', functionO 
{ 

imageOff ( "fi rst" ) ; 
return setMsgt " " ) ; 

1); 

addEventtoImagePrev, 'click', goPrev); 
addEvent(oImagePrev, 'mouseover', functionO 
( 

imageOn( "prev" ) ; 

return setMsgC'Go to previous picture"); 

1); 

addEvent(oImagePrev, 'mouseout', functionO 
( 

imageOff ( "prev" ) ; 
return setMsg( " " ) ; 

1); 

addEvent(oImageNext, 'click', goNext); 
addEvent(oImageNext, 'mouseover', functionO 
{ 

imageOn( "next" ) ; 

return setMsgC'Go to next picture"); 

I); 



214 



Chapter 14: Images and Dynamic HTML 



addEventtoImageNext, ' mouseout ' , functionO 

( 

imageOff ( "next" ) ; 
return setMsg( " " ) ; 

I); 

addEvent(oImageLast, 'click', goLast); 
addEvent(oImageLast, 'mouseover', functionO 

{ 

imageOn( "I ast" ) ; 

return setMsgC'Go to last picture"); 

I); 

addEventtoImageLast, 'mouseout', function() 
{ 

imageOff ( "I ast" ) ; 
return setMsgt "" ) ; 

I); 

} 



// initialize when the page has loaded 
addEvent(window, "load", init); 
</scri pt> 
</head> 



<body> 

< h 1 > S I ide Show Control s</hl> 



We elected to place the controller images inside a d i v element so that the images could be 
positioned or styled as a group. Each img element's onmouseover event handler (defined above) 
calls the imageOnt ) function, passing the name of the image to be swapped. Because both the 
onmouseover and onmouseout event handlers require a return true statement to work in 
older browsers, we combine the second function call (to setMsg( )) with the return true 
requirement. The setMsg( ) function always returns true and is combined with the return 
keyword before the call to the setMsg( ) function. It's just a trick to reduce the amount of code in 
these event handlers. 



<div i d="control 1 er"> 

<img s rc=" i mages/f i rstof f . png " name="first" id="first" > 
<img s rc=" i mages/prevof f . png" name="prev" id="prev" > 
<img s rc=" i mages/nextof f . png" name="next" id="next" > 
<img s rc=" i mages/1 astoff . png" name="last" id="last" > 
</div> 
</body> 
</html > 

You can see the results of this lengthy script in Figure 14-1. As the user rolls the mouse atop one of 
the images, it changes from a light to dark color by swapping the entire image. You can access the 
image files on the CD-ROM, and we encourage you to enter this lengthy listing and see the magic for 
yourself. 



215 



Part II: JavaScript Tutorial 



FIGURE 14-1 



Typical mouse rollover image swapping. 



if Slh ■Slimllfr'if* P*J|«rfn' • rtl-l"^ H 1 f i|M 


- sraor 

T A ■ P - 







Slide Show Controls 






|"to-piE.i*i i.inf 







Rollovers Without Scripts 

As cool as the rollover effect is, thanks to CSS technology, you don't always need JavaScript to accom- 
plish rollover dynamism. You can blend CSS with JavaScript to achieve the same effect. Listing 14-3 
demonstrates a version of Listing 14-2, but using CSS for the rollover effect, while JavaScript still han- 
dles the control of the slide show. 

The HTML for the buttons consists of 1 i elements that are sized and assigned background images of 
the off versions of the buttons. The text of each 1 i element is surrounded by an a element so that 
CSS : hover pseudo-elements can be assigned. (Internet Explorer through version 7 requires this, 
whereas W3C DOM browsers recognize : hover for all elements.) When the cursor hovers atop an a 
element, the background image changes to the on version. The oncl i ck event handler assignments 
remain in the script portion of the page, where they are performed after the page loads (to make sure 
the elements exist). 



LISTING 14-3 



CSS Image Rollovers 

HTML: jsb-14-03.html 

<!DOCTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Sl i de Show/Image Rol 1 overs</ti tl e> 

<link rel ="styl esheet" href="jsb-14-03.css" type="text/css"> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 14-03 . j s "></scri pt> 



216 



Chapter 14: Images and Dynamic HTML 



<script type="text/javascript"> 

</scri pt> 
</head> 
<body> 

<hl>Slide Show Control s</hl> 
<ul i d="control I er"> 

<li id="first"Xa href="//">Fi rst</a></l i > 
<li id="prev"Xa href="//">Previ ous</aX/l i > 
<li id="next"Xa href="//">Next</aX/l i > 
<li id="last"Xa href="//">Last</aX/l i > 
</ul> 
</body> 
</html > 



CSS: jsb-1403.css 



//control I er ( 

posi ti on : rel ati ve ; 
) 

//control! er I i ( 

position: absolute; list-style: none; display: block; 

height: 70px; width: 136px; 

I 

//controller a ( 

display: block; text-indent: -999px; height: 70px; 

) 



//first ( 

left: Opx; 

I 

//prev ( 

left: 146px; 

\ 

//next j 

left: 292px; 
} 

//last ( 

left: 438px; 

) 



//first a ( 

bac kg round-image: url ("firstoff.png"); 

I 

//first a:hover ( 

background-image: url ("firston.png"); 

I 

//prev a j 

background-image: url ("prevoff.png"); 

I 

//prev a:hover j 

background-image: url ("prevon.png"); 

continued 



217 



Part II: JavaScript Tutorial 



LISTING 14-3 



(continued) 



#next a ( 

background-image: url (" next off. png" 
) 

#next arhover { 

background-image: url ("next on. png") 
) 

#last a ( 

background-image: url ("lastoff.png" 

\ 

#last a:hover j 

background-image: url ("laston.png") 



JavaScript: jsb-14-03. js 

/ controller functions (disabled) 
f uncti on goFi rst ( ) 

al ert( "i n gof i rst" ) ; 

f uncti on goPrev ( ) 

al ert( "i n goprev" ) ; 

f uncti on goNext ( ) 

al ert( "i n gonext" ) ; 

functi on goLast( ) 

al ert( "i n gol ast" ) ; 



/ event handler assignments 
functi on i ni t ( ) 

if ( document . getEl ementBy Id ) 
{ 

olmageFirst = document . getEl ementBy Id ( "fi rst 
olmagePrev = document . getEl ementBy Id ( "prev " ) 
olmageNext = document . getEl ementBy Id ( "next " ) 
olmageLast = document . getEl ementBy Id (" 1 ast " ) 



el se 



olmageFirst = document . fi rst ; 
olmagePrev = document . prev ; 
olmageNext = document . next ; 
olmageLast = document . 1 ast ; 



218 



Chapter 14: Images and Dynamic HTML 



addEvent(oImageFirst 
addEvent(oImagePrev, 
addEvent( o I mage Next , 
addEvent(oImageLast, 

} 

// initialize when the page has loaded 
addEvent(wi ndow, "load", init); 



'click', goFi rst ) ; 
'click' , goPrev ) ; 
'click' , goNext ) ; 
'click', goLast ) ; 



The need to wrap the 1 i element text for Internet Explorer (which the CSS shifts completely 
off-screen, because we don't need the text) forces scripters to address further considerations. 
In this application, a click of an 1 i element is intended to run a local script, not to load an 
external URL. But the a element's default behavior is to load another URL. The # placeholder 
shown in Listing 14-3 causes the current page to reload, which will wipe away any activity of 
the oncl i ck event handler function. It is necessary, therefore, to equip each of the slide-show 
navigation functions with some extra code lines that prevent the a element from executing its default 
behavior. You'll learn how to do that in Chapter 32, "Event Objects." (It requires different syntax for 
the incompatible W3C DOM and IE event models.) 

One other note about the CSS approach in Listing 14-3 is that there is no image pre-caching taking 
place. You could add the pre-caching code for the "on" images from Listing 14-2 to get the alternative 
background images ready for the browser to swap. That's a case of CSS and JavaScript really working 
together. 



The javascript: Pseudo-URL 

You have seen instances in previous chapters of applying what is called the javascri pt : 
pseudo-URL to the href attributes of <a> and <area> tags. This technique should not be used for 
public web sites that may be accessed by browsers with scripting turned off (for which the links will 
be inactive). 

The technique was implemented to supplement the oncl i ck event handler of objects that 
act as hyperlinks. Especially in the early scripting days, when elements such as images had no 
event handlers of their own, hyperlinked elements surrounding those inactive elements allowed 
users to appear to interact directly with elements such as images. When the intended action was 
to invoke a script function (rather than navigate to another URL, as is usually the case with a 
hyperlink), the language designers invented the javascri pt: protocol for use in assignments to the 
href attributes of hyperlink elements (instead of leaving the required attribute empty). 

When a scriptable browser encounters an href attribute pointing to a javascript: pseudo-URL, 
the browser executes the script content after the colon when the user clicks the element. For example, 
the a elements of Listing 14-3 could have been written to point to javascript: pseudo-URLs that 
invoke script functions on the page, such as: 

<a href="javascript:goFirst()"> 

Note that the javascript: protocol is not a published standard, despite its wide adoption by 
browser makers. In a public web site that may be accessed by visitors with accessibility concerns 
(and potentially by browsers having little or no JavaScript capability), a link should point to a server 



219 



Part II: JavaScript Tutorial 



URL that performs an action (for example, through a server program), which in turn replicates what 
client-side JavaScript does (faster) for visitors with scriptable browsers. 



Popular Dynamic HTML Techniques 

Because today's scriptable browsers uniformly permit scripts to access each element of the 
document and automatically reflow the page's content when anything changes, a high degree of 
dynamism is possible in your applications. Dynamic HTML (DHTML) is a very deep subject, with lots 
of browser-specific peculiarities. In this section of the tutorial, you will learn techniques that work in 
Internet Explorer and W3C DOM-compatible browsers. We'll focus on two of the most common tasks 
for which DHTML is used: changing element styles and modifying document content. 

Changing style sheet settings 

Each element that renders on the page (and even some elements that don't) has a property called 
styl e. This property provides script access to all CSS properties supported for that element by the 
current browser. Property values are the same as those used for CSS specifications — frequently, a 
different syntax from similar settings that used to be made by HTML tag attributes. For example, if 
you want to set the text color of a bl ockquote element whose ID is Frank! i nQuote, the syntax is 

document . get El ementById( " Frankl i nQuote" ). styl e . col or = "rgb( 255, 255, 0)"; 

Because the CSS color property accepts other ways of specifying colors (such as the traditional hex- 
adecimal triplet — #f f f f 00), you may use those as well. 

Some CSS property names, however, do not conform to JavaScript naming conventions. Several 
CSS property names contain hyphens. When that occurs, the scripted equivalent of the property 
compresses the words and capitalizes the start of each word. For example, the CSS property 
font-weight would be set in script as follows: 

document . get El ementBy Id ( " hi ghl i ght " ) . sty 1 e . f ontWei ght = "bold"; 

A related technique properly gives responsibility for the document design to CSS. For example, if you 
define CSS rules for two different classes, you can simply switch the class definition being applied to 
the element by way of the element object's cl assName property. Let's say you define two CSS class 
definitions with different background colors: 

.normal (background-color: #ffffff); 
.highlighted { background -col or : #ff0000); 

In the HTML page, the element first receives its default class assignment as follows: 

<p id="news" cl ass="normal "> . . . </p> 

A script statement can then change the class of that element object so that the highlighted style applies 
to it: 

document.getElementById("news").className = "highlighted"; 

Restoring the original class name also restores its look and feel. This approach is also a quick way to 
change multiple style properties of an element with a single statement. 

220 



Chapter 14: Images and Dynamic HTML 



Dynamic content via W3C DOM nodes 

In Chapter 10, "Window and Document Objects," you saw the document . createEl ement( ) and 
document . createTextNode( ) methods in action. These methods create new document object 
model (DOM) objects out of thin air, which you may then modify by setting properties (attributes) 
prior to plugging the new stuff into the document tree for all to see. 

As an introduction to this technique, we'll demonstrate the steps you would go through to 
add an element and its text to a placeholding span element on the page. In this example, a 
paragraph element belonging to a class called centered will be appended to a span whose i d is 
placeholder. Some of the text for the content of the paragraph comes from a text field in a form 
(the visitor's first name). Here is the complete sequence: 

var newElem = document . createEl ement( "p" ) ; 
newEl em . cl assName = "centered"; 

var newText = document . createTextNode( "Thanks for visiting, " + 

document. forms[0].firstName. value); 
// insert text node into new paragraph 
newElem.appendChild ( newText ) ; 
// insert completed paragraph into placeholder 
document. getElement By Id ( " placeholder ").appendChild(newEl em); 

After the element and text nodes are created, the text node must be inserted into the element 
node. Because the new element node is empty when it is created, the DOM appendChi 1 d ( ) 
method plugs the text node into the element (between its start and end tags, if you could see 
the tags). When the paragraph element is assembled, it is inserted at the end of the initially 
empty span element. Additional W3C DOM methods (described in Chapter 26, "Generic HTML 
Element Objects," and Chapter 27, "Window and Frame Objects") provide more ways to insert, 
remove, and replace nodes. 

Dynamic content through the innerHTML property 

Prior to the W3C DOM specification, Microsoft invented a property of all element objects: i nner- 
HTML. This property first appeared in Internet Explorer 4, and it became popular due to its practical- 
ity. The property's value is a string containing HTML tags and other content, just as it would appear in 
an HTML document inside the current element's tags. Even though the W3C DOM working group did 
not implement this property for the published standard, the property proved to be too practical and 
popular for modern browser makers to ignore. You can find it implemented as a de facto standard in 
Mozilla-based browsers and Safari, among others. 

To illustrate the difference in the approach, the following code example shows the same content cre- 
ation and insertion as shown in the previous W3C DOM section, but this time with the i nnerHTML 
property: 

// accumulate HTML as a string 

var newHTML = "<p cl ass= ' centered ' >Thanks for v i si 
newHTML += document . forms [0] . fi rstName . val ue ; 
newHTML += "</p>"; 

// blast into placeholder element's content 
document. getElement By Id ( " placeholder").!' nnerHTML = 

221 



ting, " ; 



newHTML ; 



Part II: JavaScript Tutorial 



Although the innerHTML version seems more straightforward — and makes it easier for HTML 
coders to visualize what's being added — the DOM node approach is more efficient when the docu- 
ment modification task entails lots of content. Extensive JavaScript string concatenation operations can 
slow browser script processing. Sometimes, the shortest script is not necessarily the fastest. 

And so ends the final lesson of the JavaScript Bible tutorial. If you have gone through every lesson 
and tried your hand at the exercises, you are ready to dive into the rest of the book to learn the 
fine details and many more features of both the DOM and the JavaScript language. You can work 
sequentially through the chapters of Part III, "JavaScript Core Language Reference," and Part IV, 
"Document Objects Reference," but before too long, you should also take a peek at Chapter 48, 
"Debugging Scripts," to learn some important debugging techniques. 



Exercises 



1 . Explain the difference between a document i mg element object and the memory type of an 
image object. 

2. Write the JavaScript statements needed to pre -cache an image file named j a n e . j p g that later 
will be used to replace the document image defined by the following HTML: 

<img name="peopl e" src="john. jpg" h e i g h t = " 1 2 0 " width="100" al t="peopl e"> 

3. With the help of the code you wrote for question 2, write the JavaScript statement that replaces 
the document image with the memory image. 

4. Backward-compatible i mg element objects do not have event handlers for mouse events. How 
do you trigger scripts needed to swap images for mouse rollovers? 

5. Assume that a tabl e element contains an empty table cell (td) element whose ID is 
forwardLink. Using W3C DOM node creation techniques, write the sequence of script 
statements that create and insert the following hyperlink into the table cell: 

<a href="page4 . html ">Next Page</a> 



222 



Part III 



JavaScript Core 
Language Reference 



IN THIS PART 


Chapter 15 

The String Object 


Chapter 20 

E4X — Native XML Processing 


Chapter 16 

The Math, Number, and Boolean 
Objects 


Chapter 21 

Control Structures and Exception 
Handling 


Chapter 17 

The Date Object 


Chapter 22 

JavaScript Operators 


Chapter 18 

The Array Object 


Chapter 23 

Function Objects and Custom Objects 


Chapter 19 

JSON — Native JavaScript Object 
Notation 


Chapter 24 

Global Functions and Statements 



The String Object 




The tutorial in Chapter 8, "Programming Fundamentals, Part I," introduced 
you to the concepts of values and the types of values that JavaScript 
works with — features such as strings, numbers, and Boolean values. 
Chapter 12, "Strings, Math, and Dates," described several characteristics and 
methods of strings. In this chapter, you look more closely at the very important 
String data type, as well as its relationship to the Number data type. Along the 
way, you encounter the many ways in which JavaScript enables scripters to 
manipulate strings. 

Note 

Much of the syntax that you see in this chapter is identical to that of the Java 
programming language. Because the scope of JavaScript activity is much nar- 
rower than that of Java, you don't have nearly as much to learn for JavaScript as 
you do for Java. ■ 



IN THIS CHAPTER 



How to parse and work 
with text 

Performing search-and-replace 
operations 

Scripted alternatives to text 
formatting 



String and Number Data Types 

Although JavaScript is what is known as a "loosely typed" language, you still 
need to be aware of several data types, because of their impact on the way you 
work with the information in those forms. In this section, we focus on strings 
and two types of numbers. 



Simple strings 

A string consists of one or more standard text characters placed between match- 
ing quote marks. JavaScript is forgiving in one regard: You can use single or 
double quotes, as long as you match two single quotes or two double quotes 
around a string. A major benefit of this scheme becomes apparent when you 
try to include quoted text inside a string. For example, say that you're assem- 
bling a line of HTML code in a variable that you will eventually write to a new 



225 



Part III: JavaScript Core Language Reference 



window that is completely controlled by JavaScript. The line of text that you want to assign to a vari- 
able is the following: 

<input type="checkbox" name="candy " />Chocolate 

To assign this entire line of text to a variable, you have to surround the line in quotes. But because 
quotes appear inside the string, JavaScript (or any language) has problems deciphering where the 
string begins or ends. By carefully placing the other kind of quote pairs, however, you can make the 
assignment work. Here are two equally valid ways: 

result = '<input type="checkbox" name="candy" />Chocol ate ' ; 
result = "<input type= ' checkbox ' name='candy' />Chocol ate" ; 

Notice that in both cases, the same unique pair of quotes surrounds the entire string. Inside the string, 
two quoted strings appear that are treated as such by JavaScript. It is helpful stylistically to settle on 
one form or the other, and then use that form consistently throughout your scripts. 

If the expression you're quoting contains both apostrophes and double quotes, you need to escape one 
or the other within the string, with a backslash: 

Pat's favorite word is "syzygy." 

result = "Pat's favorite word is V'syzygy.V" 

result = 'Pat\'s favorite word is "syzygy."' 

Because escaped characters aren't as easy to read and proofread, you might want to choose a quote 
character that doesn't appear in the expression you're quoting, if possible. 

Building long string variables 

The act of joining strings together — concatenation — enables you to assemble long strings out of 
several little pieces. This feature is very important for some scripting — for example, when you need 
to build an HTML page's specifications entirely within a variable before writing the page to another 
frame, with one statement. It is often unwieldy and impractical to include such lengthy information 
in a single string on one line of code, which is why you may want to build the large string out of 
substrings. 

One tactic keeps the length of each statement in this building process short enough so that it's eas- 
ily readable in your text editor. This method uses the add-by-value assignment operator (+=) that 
appends the right-hand side of the equation to the left-hand side. Here is a simple example, which 
begins by initializing a variable, newDocument, as an empty string: 

va r newDocument = " " ; 

newDocument += "ODOCfYPE html>"; 

newDocument += "<html>" ; 

newDocument += "<head>"; 

newDocument += '<meta http-equi v="content-type" ' ; 

newDocument += ' content="text/html ; charset=utf -8"> ' ; 

newDocument += " <t i tl e>Prodi gal Summer</ti tl e>" ; 

newDocument += "</head>"; 

newDocument += "<body>"; 

newDocument += "<hl>Prodi gal Summer</hl>" ; 

newDocument += '<p cl ass="byl i ne">by Barbara Ki ngsol ver</p> ' ; 



226 



Chapter 15: The String Object 



Starting with the second line, each statement adds more data to the string being stored in 
newDocument. You can continue appending string data until the entire page's specification is con- 
tained in the newDocument variable. 

Note 

Excessive use of the add-by-value operator involving large quantities of text can become inefficient. If you are 
experiencing slow performance when accumulating large strings, try pushing your string segments into items of 
an array (see Chapter 1 8, "The Array Object"). Then use the array's j o i n ( ) method to generate the resulting 
large string value. ■ 



Joining string literals and variables 

In some cases, you need to create a string out of literal strings (characters with quote marks around 
them) and string variable values. The methodology for concatenating these types of strings is no dif- 
ferent from that of multiple string literals. The plus-sign operator does the job. Therefore, in the fol- 
lowing example, a variable contains a name. That variable value is made a part of a larger string whose 
other parts are string literals: 

teamName = prompt( "PI ease enter your favorite team:",""); 
var msg = "The " + teamName + " are victorious!"; 
al ert(msg) ; 

Some common problems that you may encounter while attempting this kind of concatenation include 
the following: 

• Accidentally omitting one of the quotes around a literal string 

• Failing to insert blank spaces in the string literals to accommodate word spacing 

• Forgetting to concatenate punctuation after a variable value 

Also, don't forget that what we show here as variable values can be any expression that evaluates to a 
string, including property references and the results of some methods. For example: 

var msg = "The name of this document is " + document . ti tl e + "."; 
al ert(msg) ; 



Special inline characters 

The way string literals are created in JavaScript makes adding certain characters to strings 
difficult — primarily quotes, carriage returns, apostrophes, and tab characters. Fortunately, JavaScript 
provides a mechanism for entering such characters into string literals. A backslash symbol, followed 
by the character that you want to appear as inline, makes that task happen. For the "invisible" 
characters, a special set of letters following the backslash tells JavaScript what to do. 

The most common backslash pairs are as follows: 

• \ " Double quote 

• \ ' Single quote (apostrophe) 

• \ \ Backslash 

• \ b Backspace 

• UTab 



227 



Part III: JavaScript Core Language Reference 



stringObject 

• \ n New line 

• \ r Carriage return 

• \ f Form feed 

Use these inline characters (also known as escaped characters, but this terminology has a different con- 
notation for Internet strings) inside quoted string literals to make JavaScript recognize them. When 
assembling a block of text that needs a new paragraph, insert the \ n character pair. Here are some 
examples of syntax using these special characters: 

msg = "I say \"trunk\" and you say V'boot.V"; 

msg = 'YoiA're doing fine.'; 

msg = "This is the first 1 i n e . \ n T h i s is the second line."; 

msg = document . ti tl e + "\n" + document . 1 i nks . 1 ength + " links present."; 

Technically speaking, a complete carriage return, as it was known in the days of the typewriter, is 
both a line feed (advance the line by one) and a carriage return (move the carriage all the way to 
the left margin). Although JavaScript strings treat a line feed (\n new line) as a full carriage return, 
you may have to construct \ r \ n breaks when assembling strings that go back to a c g i script on a 
server. The format that you use depends on the string-parsing capabilities of the c g i program. (Also 
see the special requirements for the textarea object in Chapter 36, "Text-Related Form Objects," on 
the CD.) 

It's easy to confuse the strings assembled for display in textarea objects or alert boxes with 
strings to be written as HTML. In most cases, browsers ignore carriage returns or render them 
like spaces. For HTML strings, make sure that you use standard HTML tags, such as paragraphs 
(<p> . . . </p>) and line-breaks (<br>), rather than, or in addition to, the inline return or line feed 
symbols. 



String Object 



Properties Methods 

constructor anchorU 
length big() 
prototype 1 ' blink() 

boldO 

charAt( ) 
charCodeAt( ) 
concat ( ) 

fixed ( ) 

f ontcol or( ) 
f ontsi ze( ) 
f romCharCode( 
indexOf ( ) 



228 



Chapter 15: The String Object 

stringObject 

Properties Methods 

i t a 1 i c s ( ) 

1 astlndexOf ( ) 

linkU 

1 ocal eCompare( ) 
match( ) 
repl ace( ) 
search ( ) 
si i ce( ) 
smal 1 ( ) 

spl it( ) 

stri ke( ) 

sub( ) 

substr( ) 
substri ng( ) 

sup( ) 

to Local el_owerCase( ) 
toLocaleUpperCase() 
tol_owerCase( ) 
toStri ng( ) 
toUpperCase( ) 
val ueOf ( ) 

'Member of the static String object 

Syntax 

Creating a string object: 

var myString = new Stri ng (" characters" ) ; 
Creating a string value: 

var myString = "characters"; 
Accessing static String object properties and methods: 

Stri ng . property | methodiLpa rameters^l) 



229 



Part III: JavaScript Core Language Reference 



stringObject 

Accessing string object properties and methods: 

stri ng . property | method(Lparameters^) 
Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome + 



About this object 

JavaScript draws a fine line between a string value and a string object. Both let you use the same 
methods on their contents, so that by and large, you do not have to create a string object (with the 
new Stri ng( ) constructor) every time you want to assign a string value to a variable. A simple 
assignment operation (var myString = "f red") is all you need to create a string value that 
behaves on the surface very much like a full-fledged string object. 

Where the difference comes into play is when you want to exploit the "object-ness" of a genuine string 
object, which is explained further in the discussion of the string, prototype property, later in this 
chapter. You may also encounter the need to use a full-fledged string object when passing string data 
to Java applets. If you find that your applet doesn't receive a string value as a Java String data type, 
then create a new string object via the JavaScript constructor function before passing the value to the 
applet. 

With string data often comes the need to massage string text in scripts. In addition to concatenating 
strings, at times you need to extract segments of strings, delete parts of strings, and replace one part 
of a string with some other text. Unlike many plain-language scripting languages, JavaScript is fairly 
low-level in its built-in facilities for string manipulation. This characteristic means that unless you can 
take advantage of the regular expression powers of IE4+/Mozl+ or advanced array techniques, you 
must fashion your own string handling routines out of the very elemental powers built into JavaScript. 
Later in this chapter, we provide several functions that you can use in your own scripts for common 
string handling in a manner fully compatible with older browsers. 

As you work with string values, visualize every string value as an object, with properties and methods, 
like other JavaScript objects. JavaScript defines a few properties and a slew of methods for any string 
value (and one extra property for the static String object that is always present in the context of the 
browser window). The syntax is the same for string methods as it is for any other object method: 

stri ngObject .methodi ) 

What may seem odd at first is that the stri ngObject part of this reference can be any expression 
that evaluates to a string, including string literals, variables containing strings, methods or functions 
that return strings, or other object properties. Therefore, the following examples of calling the tollp- 
perCase( ) method are all valid: 

"blah blah bl ah" .toUpperCase( ) 

yourName.toUpperCase( ) // yourName is a variable containing a string 
window. promptC'Enter your name" , "" ) .toUpperCase( ) 

document . forms [0] . entry . val ue . toUpperCase( ) // entry is text field object 

A very important (and often misunderstood) concept to remember is that invoking a string method 
does not change the string object that is part of the reference. Rather, the method returns a string 
value, which can be used as a parameter to another method or function call, or assigned to a 
variable. 



230 



Chapter 15: The String Object 



stringObject. length 

Therefore, to change the contents of a string variable to the results of a method, you must use an 
assignment operator, as in: 

yourName = yourName . toUpperCase ( ) ; // variable is now all uppercase 

Properties 

constructor 

Value: Function reference Read/Write 
Compatibility: WinIE4+, MacIE4+, NN4+, Moz4-, Safari4-, Opera4-, Chrome4- 

The constructor property is a reference to the function that was invoked to create the current 
string. For a native JavaScript string object, the constructor function is the built-in Stri ng( ) con- 
structor. 

When you use the n ew St r i n g ( ) constructor to create a string object, the type of the value returned 
by the constructor is object (meaning that the typeof operator returns object). Therefore, you 
can use the constructor property on an object value to see if it is a string object: 

if (typeof someValue == "object" ) 
{ 

if ( someVa I ue . cons t ructor == String) 
{ 

// statements to deal with string object 

} 

} 

Although the property is read/write, and you can assign a different constructor to the 

Stri ng . prototype, the native behavior of a Stri ng object persists through the new constructor. 

Example 

Use The Evaluator (see Chapter 4) to test the value of the constructor property. One line at a time, 
enter and evaluate the following statements into the top text box: 

a = new Stri ng( "abed" ) 
a . constructor == String 
a . constructor == Number 

Related Items: prototype property 

1 ength 

Value: Integer Read/Write 
Compatibility: WinIE34-, MacIE34-, NN24-, Moz4-, SafarH-, Opera4-, Chrome + 

The most frequently used property of a string is 1 ength. To derive the length of a string, read its 
property as you would read the length property of any object: 

stri ng. 1 ength 



231 



Part III: JavaScript Core Language Reference 



sfringOb/ecf.prototype 

The length value represents an integer count of the number of characters within the string. Spaces 
and punctuation symbols count as characters. Any backslash special characters embedded in a string 
count as one character, including such characters as newline and tab. Here are some examples: 

" Li ncol n " . 1 ength // result = 7 
"Four score" . 1 ength // result = 10 
"0ne\ntwo" . 1 ength // result = 7 
"".length // result = 0 

The 1 ength property is commonly summoned when dealing with detailed string manipulation in 
repeat loops. For example, if you want to iterate through every character in a string, and somehow 
examine or modify each character, you would use the string's length as the basis for the loop counter. 

prototype 

Value: String object Read/Write 
Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari+, Opera+, Chrome + 

String objects defined with the new Stri ng( "stringVa lue" ) constructor are robust objects 
compared to run-of-the-mill variables that are assigned string values. You certainly don't have to cre- 
ate this kind of string object for every string in your scripts, but these objects do come in handy if 
you find that strings in variables go awry. This happens occasionally while trying to preserve string 
information as script variables in other frames or windows. By using the Stri ng object constructor, 
you can be relatively assured that the string value will be available in the distant frame when needed. 

Another benefit to using true String objects is that you can assign prototype properties and me- 
thods to all string objects in the document. A prototype is a collection of properties and methods that 
become part of every new object created after the prototype items are added. As an example, you 
may want to define a new method for transforming a string that isn't already defined by the JavaScript 
Stri ng object. Listing 15-1 shows how to create and use such a prototype. 

Note 

The property assignment event-handling technique employed throughout the code in this chapter, and much of 
the book, is addEvent( ), a cross-browser event handler explained in detail in Chapter 32, "Event Object." 

The addEvent( ) function is part of the script file jsb global . js, located on the accompanying CD-ROM 
in the Content/ folder, where it is accessible to all chapters' scripts. ■ 



LISTING 15-1 



Using the String Object Prototype 

HTML: jsb-15-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Using the String Object Prototype</ti tl e> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 15-01 . j s "></scri pt> 
</head> 



232 



Chapter 15: The String Object 



sfn'ngOfe/eef.prototype 

<body> 

<hl>Using the String Object Prototype</hl> 
<form acti on = " i ni ti al Cap . php"> 

<P> 

< I a be I f or="entry ">Enter one or more words to be Initial Capped : </l abel > 

</p> 
<P> 

<input type="text" id="entry" name="entry " value=""> 
<input type="button" id="do-it" val ue=" I ni ti al Caps"> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-15-01.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to critical elements 

var oButton = document . getEl ementBy Id (' do- i t ') ; 

var oEntry = document . getEl ementBy Id (' entry ') ; 

// if they al 1 exi st . . . 
if (oButton && oEntry) 
{ 

// apply behavior to button 
addEvent ( oButton , 'click', dolt); 

} 




// try out the new String method 

functi on doIt( ) 

{ 

// point to i nput field 

var oEntry = document . getEl ementBy Id (' entry ') ; 

// use the new method to update the input text 
oEntry. value = oEntry . val ue . i ni ti al Caps () ; 

} 



// add a new method to the String prototype 
// to capitalize the first letter of each word 

Stri ng . prototype . i ni ti al Caps = functionO 

continued 



233 



Part III: JavaScript Core Language Reference 



stringObject.char AtQ 



LISTING 15-1 



(continued) 



{ 

II get the input text 

var sText = thi s . toStri ng ( ) ; 

// separate individual words 
var aWords = sText . spl i t( ' '); 



// capitalize each word 

for (var i = 0; i < aWords . 1 ength ; i++) 

{ 

var slnitial = aWords [ i ]. charAt( 0 ) ; 
var sRemainder = aWords [ i ]. substr( 1 ) ; 

aWords[i] = s I ni ti al . toUpperCase ( ) + sRemai nder . toLowerCase ( ) ; 

} 

// reassemble the array of words back into a string 
return aWords . j oi n ( ' ' ) ; 

1 



Note 

Many of the HTML example pages in this book include a form action to post input to a server-side PHP 
program — as a reminder that it's important to make sure that our pages can function even when JavaScript is 
not running. The server-side scripts themselves do not exist and are outside the scope of this book. If written, 
they would perform essentially the same operations as the JavaScript logic does. ■ 



The core of the JavaScript in Listing 15-1 is the last block, where we add the i ni ti al Caps ( ) 
method to the String object prototype, and spell out what that method does. Similar to 
most object methods, this new one doesn't modify the original string itself, but rather returns 
a value we can use for any purpose we want. Here, we grab the contents of the input field entry, 
transform it with initial Ca ps ( ) , and use that new value to reset the input field contents. 

Modifying object prototypes is a powerful way to add new features to the JavaScript language 
on-the-fly. 

In the next sections, we divide String object methods into two distinct categories. The first, pars- 
ing methods, focuses on string analysis and character manipulation within strings. The second group 
formatting methods, is devoted entirely to assembling strings in HTML syntax for those scripts that 
assemble the text to be written into new documents or other frames. 



Parsing methods 

string. charAt( index) 

Returns: One-character string 

Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome+ 

234 



Chapter 15: The String Object 



stringObject.fromCharCodeQ 

Use the S tr i ng. ch a rAt( ) method to read a single character from a string when you know the 
position of that character. For this method, you specify an index value in the string as a parameter to 
the method. The index value of the first character of the string is 0. To grab the last character of a 
string, mix string methods: 

tnyStri ng . charAt(myStri ng . 1 ength - 1) 

If your script needs to get a range of characters, use the string, substring! ) method. Using 
str i ng.substringO to extract a character from inside a string is a common mistake — the 
string. charAt( ) method is more efficient. 



Example 

Enter each of the following statements into the top text box of The Evaluator: 

a = "banana daiquiri" 

a . charAt ( 0 ) // resul t = ' b ' 

a.charAt(5) // result = 'a' (the third 'a') 

a.charAt(6) // result = ' ' (space) 

a.charAt(20) // result = '' (empty string) 

Related Items: string. 1 astlndexOf ( ), string . i ndexOf ( ), str fng. substri ng( ) 
methods 

s tr 7 ng. ch a rCodeAtC [ /ncfex] ) 

strfng.fromCharCodeCnt/ml [, numZ [, ... nt/mn]]) 

Returns: Integer code number for a character; concatenated string value of code numbers supplied as 
parameters 

Compatibility: WinIE4+, MacIE4+, NN4+, Moz4-, Safari4-, Opera4-, Chrome4- 

Conversions from plain language characters to their numeric equivalents have a long tradition in com- 
puter programming. For many years, the most common numbering scheme was the ASCII standard, 
which covers the basic English alphanumeric characters and punctuation within 128 values (numbered 
0 through 127). An extended version with a total of 256 characters, with some variations, depending 
on the operating system, accounts for other roman characters in other languages, particularly accented 
vowels. To support all languages, including pictographic languages, and other non-Roman writing 
systems, a world standard called Unicode provides space for thousands of characters. All modern 
browsers work with the Unicode system. 

In JavaScript, character conversions are handled by string methods. The two methods that perform 
character conversions work in very different ways syntactically. The first, string . charCodeAt( ), 
converts a single string character to its numeric equivalent. The string being converted is the one to 
the left of the method name — and the string may be a literal string or any other expression that eval- 
uates to a string value. If no parameter is passed, the character being converted is by default the first 
character of the string. However, you can also specify a different character as an index value into the 
string (first character is 0), as demonstrated here: 

"a be" . charCodeAt( ) // result = 97 
"abc" .charCodeAt(O) // result = 97 
"abc" .charCodeAt(l) // result = 98 



235 



Part III: JavaScript Core Language Reference 



sfringOfe/ecf.fromCharCodeO 

If the string value is an empty string, or the index value is beyond the last character, the result 
is NaN. 

To convert numeric values to their characters, use the St r i ng . f romCha rCode ( ) method. Notice 
that the object beginning the method call is the static St r i ng object, not a string value. Then, as 
parameters, you can include one or more integers, separated by commas. In the conversion process, 
the method combines the characters for all of the parameters into one string, an example of which is 
shown here: 

St ri ng . f romCha rCode ( 97 , 98, 99) // result "abc" 



Note 

Although most modern browsers support character values across the entire Unicode range, the browser won't 
properly render characters above 255 unless the computer is equipped with language and font support for the 
designated language. To assist with Unicode character display, all our HTML documents begin with declarations 
of UTF-8 character encoding. ■ 



FIGURE 15-1 



Conversions from text characters to ASCII values and vice versa. 



Character Codes - Mozllla Flrefo* 


Jnl*l 


Be Eett Sflew History Bookmarks tools Help 


character codes 


Character Codes 




Capturing Character Codes 




Stkel auv ttxt art ibis (jagt mi see die cjaraciei code of lhe rase cbatoetci 




ClwjKMT Cs*: ffiS 




Converting Codes to Characters 




Enter ivitotf>-J55|6( 




EaK.i™kit 0-155: |?s 




Enid ■ value 4-2S5. |?1 




ShnrStov | R?sdt |DOG 




Done 



236 



Chapter 15: The String Object 



stringObject.fromCharCodeQ 

Example 

Listing 15-2 provides examples of both methods on one page. Moreover, because one of the 
demonstrations relies on the automatic capture of selected text on the page, the scripts include code 
to accommodate the different handling of selection events, and the capture of the selected text in a 
variety of browsers. 

After you load the page, select part of the body text anywhere on the page. If you start the selection 
with the lowercase letter "a," the character code displays as 97. 

Try entering numeric values in the three fields at the bottom of the page. Values below 32 are 
ASCII control characters that most fonts represent as blanks or hollow squares. But try other 
values to see what you get. Notice that the script passes all three values as a group to the 
St ri ng . f romCha rCode ( ) method, and the result is a combined string. Thus, Figure 15-1 shows 
what happens when you enter the uppercase ASCII values for a three-letter animal name. 



LISTING 15-2 



Character Conversions 



HTML: jsb-15-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type' 
<ti tl e>Character Codes</ti tl e> 
<script type="text/ j avascri pt" 
<script type="text/ j avascri pt" 

</head> 

<body> 

<hl>Character Codes</hl> 



con ten t= " text/ h tml ; chars et=utf -8" > 

src=". . / jsb-gl obal .js"X/script> 
src="jsb-15-02.js"X/script> 



<form action="show-string.php"> 

<h2>Capturi ng Character Codes</h2> 

<p>Select any text on this page and see the character code of the first 

character. </p> 

<P> 

< 1 a be 1 f or="di spl ay ">Character Code : </l abel > 

<input type="text" id="display" name="di spl ay " size="3" /> 

</p> 



<h2>Converti ng Codes 
<P> 



to Characters</h2> 



<1 abel 
<i nput 

</p> 
<P> 

<1 abel 
<i nput 

</p> 
<P> 



f or="entry 1 ' 
type="text" 



f or="entry2' 
type="text" 



>Enter a va" 
i d="entry 1 " 



>Enter a va" 
i d="entry2" 



ue U 
name 



ue U 
name 



255 : </l abel > 
! "entryl" size= 



255 : </l abel > 
= "entry2" size= 



'6" /> 



/> 



continued 



237 



Part III: JavaScript Core Language Reference 



sfringOfe/ecf.fromCharCodeO 



LISTING 15-2 



(continued) 



<label f or="entry3">Enter a value 0-255 : </l abel > 

<input type="text" id="entry3" name="entry3" size="6" /> 

</p> 
<P> 

<input type="button" i d="showstr" value="Show String" /> 
< 1 abel for=" result") Re sult:</label> 

<input type="text" id="result" name="resul t" size="5" /> 

</p> 
</ f orm> 
</body> 
</html > 



JavaScript: jsb-1502.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

// show character code when text is selected 
addEvent ( document , 'mouseup', showCharCode) ; 



f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld ) 

{ 

// point to critical element 

var oButton = document . getEl ementByld (' showstr ') ; 

// if it exi sts . . . 

if (oButton) 

{ 

// apply behavior to button 

addEvent ( oButton , 'click', showString); 

} 



// show the text characters represented by the numbers entered 

function showStringO 

{ 

var oEntryl = document . getEl ementByld (' entry 1 ') ; 
var oEntry2 = document . getEl ementByld (' entry2 ') ; 
var oEntry3 = document . getEl ementByld (' entry3 ') ; 
var oResult = document . getEl ementByld (' resul t ') ; 

oResul t . val ue = Stri ng . f romCharCode ( oEntry 1 . val ue , oEntry2 . val ue , oEntry3 . val ue ) ; 

) 



238 



Chapter 15: The String Object 



stringObject. i ndexOf () 

// display the character code of the selected text 
// (first character only) 
function showCharCode( ) 
{ 

var thefext = ""; 

var oDisplay = document . getEl ementBy Id (' di spl ay ') ; 

// get the selected text using various browsers' methods 
if ( wi ndow . getSel ecti on ) 

theText = wi ndow . getSel ecti on (). toStri ng () ; 
else if ( document . getSel ecti on ) 

theText = document . getSel ecti on () ; 
else if ( document . sel ecti on && document . sel ecti on . createRange ) 

theText = document . sel ecti on . createRange (). text ; 

// display the result if any 
if (theText) 

oDi spl ay . val ue = theText . charCodeAt () ; 

el se 

oDi spl ay . val ue = " "; 

} 



s tr ing. concat ( string2) 

Returns: Combined string 

Compatibility: WinIE4+, MacIE4+, NN4+, Moz4-, Safari4-, Opera4-, Chrome4- 

JavaScript's add-by-value operator (+=) provides a convenient way to concatenate strings. Most 
browsers, however, include a string object method that performs the same task. The base string 
to which more text is appended is the object or value to the left of the period. The string to be 
appended is the parameter of the method, as the following example demonstrates: 

"abc".concat("def") // result: "abcdef" 

As with the add-by-value operator, the c o n c a t ( ) method doesn't know about word spacing. You are 
responsible for including the necessary space between words if the two strings require a space between 
them in the result. 

Related Items: Add-by-value (+=) operator 

string, i ndexOf ( searchString [, start Index']) 



239 



Part III: JavaScript Core Language Reference 



stringObject. last I ndexOf () 

Returns: Index value of the character within string where searchString begins 

Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome + 

Like some programming languages' offset string function, JavaScript's indexOf ( ) method enables 
your script to obtain the position in the main string where a search string begins. Optionally, you can 
specify where in the main string the search should begin — but the returned value is always relative 
to the very first character of the main string. Like all string object methods, index values start their 
count with 0. If no match occurs within the main string, the returned value is - 1. Thus, this method 
is also a convenient way to determine whether one string contains another, regardless of position. 



Example 

Enter each of the following statements (up to but not including the "//" comment symbols) into the 
top text box of The Evaluator (you can simply replace the parameters of the i ndexOf ( ) method for 
each statement after the first one). Compare your results with the results shown below. 

a = "bananas" 



a 


i ndexOf ( 


"b") 


// 


resu 


t = 


0 


( i ndex 


of 1st letter is 


a 


i ndexOf ( 


"a") 


// 


resu 


t = 


1 






a 


i ndexOf ( 


"a",D 


// 


resu 


t = 


1 


(start 


from 2nd 1 etter ) 


a 


i ndexOf ( 


"a", 2) 


// 


resu 


t = 


3 


(start 


from 3rd 1 etter ) 


a 


i ndexOf ( 


"a" ,4) 


// 


resu 


t = 


5 


(start 


from 5th 1 etter ) 


a 


i ndexOf ( 


"nan") 


// 


resu 


t = 


2 






a 


i ndexOf ( 


" n a s " ) 


// 


resu 


t = 


4 






a 


i ndexOf ( 


"s") 


// 


resu 


t = 


6 






a 


i ndexOf ( 


"z") 


// 


resu 


t = 


-1 


(no "z 


" in string) 



Related Items: string. 1 ast I ndexOf ( ), str fng.charAtO, str fng.substringO methods 

string. 1 astlndexOf ( searchStringl , start Index] ) 

Returns: Index value of the last character within the string where sectrchString begins 

Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome + 

The string . 1 astlndexOf ( ) method is closely related to the method string . i ndexOf ( ). 
The only difference is that this method starts its search for a match from the end of the string 
(str 7 riff. length - 1) and works its way backward through the string. All index values are still 
counted, starting with 0, from the front of the string. The examples that follow use the same values as 
in the examples for str i ng . i ndexOf ( ) so that you can compare the results. In cases where only 
one instance of the search string is found, the results are the same; but when multiple instances of the 
search string exist, the results can vary widely — hence the need for this method. 



Example 

Enter each of the following statements (up to, but not including the "//" comment symbols) into 
the top text box of The Evaluator (you can simply replace the parameters of the 1 a st I ndexOf ( ) 
method for each statement after the first one). Compare your results with the results shown below. 

a = "bananas" 

a . 1 astlndexOf ( "b" ) // result = 0 (index of 1st letter is zero) 

a . 1 astlndexOf ( "a" ) // result = 5 

a . 1 ast I ndexOf ( " a " , 1 ) // result = 1 (from 2nd letter toward the front! 

a . 1 ast I ndexOf ( " a " , 2 ) // result = 1 (start from 3rd letter working 



240 



Chapter 15: The String Object 



stringObject. match () 



a . 1 astlndexOf ( "z" ) 



a.lastlndex0f("a",4) 
a . 1 astlndexOf ( "nan" ) 
a . 1 ast I ndexOf ( " nas " ) 
a . 1 ast I ndexOf ( " s " ) 



// result 

// result 

// result 

// result 

// result 



toward front) 
3 (start from 5th letter) 
2 [except for -1 Nav 2.0 bug] 
4 
6 

- 1 (no " z " in string) 



Related Items: string. 1 astlndexOf ( ), str fng.charAtO, str 7 ng.substringO methods 

string^ oca 1 eCompa re ( str ing2) 

Returns: Integer 

Compatibility: WinIE5.5+, MacIE-, NN6+, Moz+, Safan+, Opera+, Chrome+ 

The 1 ocal eComparef ) method lets a script compare the cumulative Unicode values of two strings, 
taking into account the language system for the browser. This method is necessitated by only a few 
human languages (Turkish is said to be one). If the two strings, adjusted for the language system, are 
equal, the value returned is zero. If the string value on which the method is invoked (meaning the 
string to the left of the period) sorts ahead of the parameter string, the value returned is a negative 
integer; otherwise the returned value is a positive integer. 

The ECMA standard for this method leaves the precise positive or negative values up to the browser 
designer. NN6+ calculates the cumulative Unicode values for both strings and subtracts the string 
parameter's sum from the string value's sum. IE5.5+ and FF1+, on the other hand, return -1 or 1 if 
the strings are not colloquially equal. 

Related Items: string, to Local eLowerCase ( ), string, to Local eUpperCaseC ) methods 
string. match( regExpression) 

Returns: Array of matching substrings 

Compatibility: WinIE4+, MacIE4+, NN4+, Moz4-, Safari4-, Opera4-, Chrome4- 

The str i n g . m a t c h ( ) method relies on the R e g E x p (regular expression) obj ect to carry out a match 
within a string. The string value under scrutiny is to the left of the dot, whereas the regular expres- 
sion to be used by the method is passed as a parameter. The parameter must be a regular expression 
object, created according to the two ways these objects can be generated. 

This method returns an array value when at least one match turns up; otherwise the returned value 
is null. Each entry in the array is a copy of the string segment that matches the specifications of the 
regular expression. You can use this method to uncover how many times a substring or sequence of 
characters appears in a larger string. Finding the offset locations of the matches requires other string 
parsing. 

Example 

To help you understand the stri ng .match!, ) method, Listing 15-3 provides you with a regular 
expression workshop. Three input controls let you set up a test: the first is for the long string, to be 
examined by the method; the second is for a regular expression; and the third is a checkbox that 
lets you specify whether the search through the string for matches should be case-sensitive. Some 
default values are provided, in case you're not yet familiar with the syntax of regular expressions (see 
Chapter 45 on the CD-ROM). After you click the "Execute match()" button, the script creates a regular 
expression object out of your input, performs the String, match ( ) method on the big string, and 



241 



Part III: JavaScript Core Language Reference 



stringObjectmaXdnQ 

reports two kinds of results to the page. The primary result is a string version of the array returned by 
the method; the other is a count of items returned. 



LISTING 15-3 



Regular Expression Match Workshop 

HTML: jsb-15-03.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Regul ar Expression Match Workshop</ti tl e> 
<script type=" text /javascript" src="../jsb-global . js "></scn'pt> 
<script type="text/ j avascri pt" src="j sb- 15-03 . j s "></scri pt> 

</head> 

<body> 

<hl>Regular Expression Match Workshop</hl> 

<form action="regexp -match. php"> 

<P> 

< 1 a be 1 f or="stri ng">Enter a main stri ng : </l abel > 
<input type="text" id="string" name="stri ng" size="60" 
value="Many a maN and womAN have meant to visit GerMAny." /> 

</p> 
<P> 

< 1 abel for="pattern">Enter a regular expression to match : </l abel > 

<input type="text" id="pattern" name="pattern" size="25" val ue="\wa\w" /> 

<input type="checkbox" id="caseSens" name="caseSens" /> 
< 1 abel f or= "caseSens">Case- sens i ti ve</l abel > 

</p> 
<P> 

<input type="button" id="button" val ue="Execute match()" /> 
<input type="reset" /> 

</p> 
<P> 

< 1 abel f or=" result") Re sult:</label> 

<input type="text" id="result" name="resul t" size="40" /> 

</p> 
<P> 

< 1 abel for="count">Count:</label> 

<input type="text" id="count" name="count" size="3" /> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-15-03.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 



242 



Chapter 15: The String Object 



stringObject. match () 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to critical element 

var oButton = document . getEl ementBy Id( ' button ') ; 

// if it exi sts . . . 

if (oButton) 

f 

// apply behavior to button 
addEvent ( oButton , 'click', doMatch); 

I 

I 

} 

// perform regular expression match using input values 

f uncti on doMatch ( ) 

{ 

// gather input values 

var oString = document . getEl ementBy Id (' stri ng ') ; 
var sString = oStri ng . val ue ; 

var oPattern = document . getEl ementBy Id( ' pattern ') ; 

var oCaseSensi ti vi ty = document . getEl ementBy Id (' caseSens ') ; 

var sFlags = 'g'; // g = find all 

if {! oCaseSensi ti vi ty . checked ) sFlags += 'i'; // i = case- i nsensi ti ve 

// create regular expression object 

var oRegExp = new RegExp ( oPattern . val ue , sFlags); 

// perform match 

var aResult = sStri ng . match ( oRegExp ) ; 
// display results 

var oResult = document . getEl ementBy Id (' resul t ') ; 
var oCount = document . getEl ementBy Id (' count ') ; 

// got matches? 
if (aResult) 
{ 

oResul t . val ue = aResul t . toStri ng ( ) ; 
oCount. value = aResul t . I ength ; 

} 

el se 
{ 

oResul t . val ue = "<no matches)"; 
oCount. value = ""; 

} 



243 



Part III: JavaScript Core Language Reference 



stringObject.rep\aceQ 

The default value for the mam string has unusual capitalization intentionally. The capitalization lets 
you see more clearly where some of the matches come from. For example, the default regular expres- 
sion looks for any three-character string that has the letter "a" in the middle. Six string segments 
match that expression. With the help of capitalization, you can see where each of the four strings con- 
taining "man" is extracted from the main string. The following table lists some other regular expres- 
sions to try with the default main string. 



RegExp 


Description 


man 


Both case-sensitive and not 


man\b 


Where "man" is at the end of a word 


\bman 


Where "man" is at the start of a word 


me*an 


Where zero or more "e" letters occur between "m" and "a" 


. a . 


Where "a" is surrounded by any one character (including space) 


\sa\s 


Where "a" is surrounded by a space on both sides 


z 


Where a "z" occurs (none in the default string) 



In the scripts for Listing 15-3, if the S tring. ma tch( ) method returns null, you are informed 
politely, and the count field is emptied. 

Related Items: RegExp object (see Chapter 45 on the CD-ROM) 

s tr / ng. repl ace ( regExpression, repl aceStri ng) 

Returns: Changed string 

Compatibility: WinIE4+, MacIE44-, NN44-, Moz-I-, Safari-!-, Opera4-, Chrome4- 

Regular expressions are commonly used to perform search-and-replace operations. In conjunction with 
the stri ng . search( ) method, JavaScript's string. replace() method provides a simple frame- 
work in which to perform this kind of operation on any string. 

A replace operation using RegExp requires three components. The first is the main string that is the 
target of the operation. Second is the regular expression pattern to search for. And third is the string 
to replace each instance of the text found by the operation. 

stringToSearch. repl ace( pattern , repl acementStri ng) ; 

For the string . repl ace() method, the main string is the string value, or object referenced, to 
the left of the period. This string can also be a literal string (that is, text surrounded by quotes). The 
regular expression to search for is the first parameter, whereas the replacement string is the second 
parameter. 



244 



Chapter 15: The String Object 



stringObject.rep\aceQ 

The regular expression definition determines whether the replacement is of just the first match 
encountered in the main string, or all matches in the string. If you add the g flag to the end 
of the regular expression, then one invocation of the rep I ace( ) method performs a global 
search-and-replace throughout the entire main string. 

As long as you know how to generate a regular expression, you can easily use the string 

. repl ace( ) method to perform simple replacement operations. But using regular expressions can 

make the operation more powerful. Consider these soliloquy lines by Hamlet: 

To be, or not to be: that is the question: 
Whether 'tis nobler in the mind to suffer 

If you wanted to replace both instances of "be" with "exist," you can do it in this case by 
specifying 

var regexp = /be/g; 
soliloquy.replace(regexp, "exist"); 

But you can't always be assured that the letters "b" and "e" will be standing alone as a word. What 
happens if the main string contains the word "being" or "saber"? The above example would replace 
the "be" letters in them as well. 

Rescue comes from special characters that better define what to search for. In the example here, the 
search is for the word "be." Therefore, the regular expression surrounds the search text with word 
boundaries (the \b special character), as in 

var regexp = /\bbe\b/g; 
soliloquy.replace(regexp, "exist"); 

This syntax also takes care of the fact that the first two "be" words are followed by punctuation, rather 
than a space, as you may expect for a freestanding word. For more about regular expression syntax, 
see Chapter 45 on the CD-ROM. 

Example 

The page created by Listing 15-4 lets you practice with the string, repl ace ( ) and 
String, search ( ) methods, and regular expressions, in a friendly environment. The source 
text is a five-line excerpt from Hamlet. You can enter the regular expression to search on, and the 
replacement text as well. Note that the script completes the job of creating the regular expression 
object, so that you can focus on the other special characters used to define the matching string. All 
replacement activities act globally because the g flag is automatically appended to any expression you 
enter. 

Default values in the fields replace the contraction 'tis with "it is" after you click the "Execute 
replaceO" button (see Figure 15-2). Notice that the backslash character in front of the apostrophe 
of 'tis (in the string assembled in mai nStri ng) makes the apostrophe a non-word boundary, and 
thus allows the \ B ' t regular expression to find a match there. As described in the section on the 
str7'ng.search( ) method, the button connected to that method returns the offset character 
number of the matching string (or - 1 if no match occurs). 



245 



Part III: JavaScript Core Language Reference 



stringObject.rep\ace() 



FIGURE 15-2 



Using the default replacement regular expression. 



"'Regular Expression Replace and Search - Mozllla Firefox 


-Inlxi 


Die Ldl Vjew Hl&xv Eookmaks luoli Help 


linjular LiiirmiiCm llepl... | 






Regular Expression Replace and Search 




Text U5*i trr stswij rrpiac*; '} and strinr s? ardu"l methods* 






To b#, u.- net ts ba: '..i*. 1 . *» li-.p qu*-»Eiori: 
■Ttretber 'gib nobler in i-Iae mind to sulCer 
TtiE sliiiga uid ursui of ■rjr^aijeau.a rcctunc, 
Of tp t*fev B tttt 4Pi 3 bv t ■ ■ pf troublt ip 
.'.r.^ ty oppoclnn ecrl then 






Eniei a t?piai eijxmvm pun cm m match fiB'l V Cnie- 






Enter a string tn 3frla« the matdbku; songs |h 






rxe-i-ra rap-jcafl! 1 Rnsfll | Eaetirtfl soarchfi | 






f>-l!|l 






To be, or not cc be; cmac ae- rfce rjuesdori; 
"<i. . lr 1.9 in j U autleE 
TtM plinrje »nd irrcwv of ^utr»7?a«i fffrtun-p., 
Or co "cake nrrea avueisc ft sea of -raublea* 
*&1 by uKpuiiin: tel in*n.- 












Dorn? 







LISTING 15-4 



Lab for sfri'ng.replaceO and sfr/ng.search() 

HTML: jsb-15-04.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Regul ar Expression Replace and Search</ti tl e> 
<script type=" text /javascript" src=". . / jsb-gl obal .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 15-04 . j s "></scri pt> 

</head> 

<body> 

<hl>Regular Expression Replace and Search</hl> 

<form action="regexp-replace.php"> 

<P> 

< 1 a be 1 f or="source">Text used for stri ng . repl ace ( ) and 



246 



Chapter 15: The String Object 



stringObject.repfoceQ 

stri ng . search ( ) methods : </l abel > 

</p> 
<P> 

<textarea id="source" name="source" cols="60" rows="5"> 
To be, or not to be: that is the question: 
Whether 'tis nobler in the mind to suffer 
The slings and arrows of outrageous fortune, 
Or to take arms against a sea of troubles, 
And by opposing end them. 
</textarea> 

</p> 

<P> 

< I abel for="pattern">Enter a regular expression pattern to match : </l abel > 
<input type="text" id="pattern" name="pattern" size="25" value="\B't" /> 

<input type="checkbox" id="caseSens" name="caseSens" /> 
< I abel for="caseSens">Case-sensitive</label> 

</p> 
<P> 

< I abel for="repl acement">Enter a string to replace 

the matching stri ngs : </l abel > 
<input type="text" id="repl acement" name="repl acement" 
size="30" value="it " /> 

</p> 
<P> 

<input type="button" id="button-repl ace" val ue="Execute replace()" 

onclick="doReplace(this.form)" /> 
<input type="reset" /> 

<input type="button" id="button-search" val ue="Execute search()" 
oncl ick="doSearch(this.form)" /> 

</p> 
<P> 

<l abel for="result">Result:</label><br /> 

<textarea id="result" name="resul t" cols="60" rows="5"X/textarea> 

</p> 
</ form) 
</body> 
</html > 

JavaScript: jsb-1504.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// check for critical elements 

var oSource = document . getEl ementBy Id (' source ') ; 

var oPattern = document . getEl ementBy Id( ' pattern ') ; 

continued 



247 



Part III: JavaScript Core Language Reference 



stringObjectreplaceQ 



LISTING 15-4 



(continued) 



var oCaseSensi ti vi ty = document . getEl ementBy Id (' caseSens ') ; 

var oRepl acement = document . getEl ementBy Id (' repl acement ') ; 

var oButtonRepl ace = document . getEl ementBy Id (' button - repl ace ') ; 

var oButtonSearch = document . getEl ementBy Id (' button -search ') ; 

var oResult = document . getEl ementBy Id( ' resul t ') ; 

// if they al 1 exi st . . . 

if (oSource && oPattern && oCaseSensi ti vi ty && oReplacement 
&& oButtonRepl ace && oButtonSearch && oResult) 

{ 

// apply behaviors 

addEvent(oButtonRepl ace, 'click', doReplace); 
addEvent ( oButtonSearch , 'click', doSearch); 

} 

el se 
{ 

al ert ( ' Cri ti cal element not found'); 

1 

1 

} 



f uncti on doRepl ace ( ) 
{ 

var sSource = document . getEl ementBy Id (' source '). val ue ; 

var sReplacement = document . getEl ementBy Id( ' repl acement '). val ue ; 

var sPattern = document . getEl ementBy Id( ' pattern '). val ue ; 

var sFlags = 'g'; // g = find all; i = case- i nsensi ti ve 

if (! document . getEl ementBy Id (' caseSens '). checked ) sFlags += ' i ' ; 

// create regular expression object 

var oRegExp = new RegExp ( sPattern , sFlags); 

// perform replace 

var sResult = sSource . repl ace ( oRegExp , sReplacement); 
// display results 

document . getEl ementBy Id (' resul t '). val ue = sResult; 

) 



functi on doSearch( ) 
{ 

var sSource = document . getEl ementBy Id( ' source '). val ue ; 
var sPattern = document . getEl ementBy Id( ' pattern '). val ue ; 
var sFlags = 'g'; // g = find all; i = case- i nsensi ti ve 

if (! document . getEl ementBy Id (' caseSens '). checked ) sFlags += 'i'; 

// create regular expression object 



248 



Chapter 15: The String Object 



stringObject. s I i ce () 

var oRegExp = new RegExp ( sPattern , sFlags); 
// perform replace 

var sResult = sSource.search(oRegExp) ; 
// display results 

document . getEl ementBy Id (' resul t '). val ue = sResult; 

) 



Related Items: string, match ( ) method; RegExp object 

string. search ( regExpressi on) 

Returns: Offset integer 

Compatibility: WinIE4+, MacIE4+, NN44-, Moz4-, Safari4-, Opera 4-, Chrome + 

The results of the s tr ing . sea rch ( ) method may remind you of the str ing. i ndexOf C ) 
method. In both cases, the returned value is the character number where the matching string first 
appears in the main string, or - 1 if no match occurs. The big difference, of course, is that the 
matching string for string . search( ) is a regular expression. 

Example 

Listing 15-4, which illustrates the string.replace() method, also provides a laboratory to experi- 
ment with the string. search( ) method. 

Related Items: string. match( ) method; RegExp object 

string. sMceistartlndex [, endlndex~\) 

Returns: String 

Compatibility: WinIE44-, MacIE44-, NN44-, Moz4-, Safari4-, Opera 4-, Chrome + 

The string . si ice() method resembles the method string . substri ng( ), in that both let you 
extract a portion of one string and create a new string as a result (without modifying the original 
string). A helpful improvement in string . si i ce( ), however, is that specifying an ending index 
value relative to the end of the main string is easier. 

Using str i ng. substri ng() to extract a substring that ends before the end of the string requires 
machinations such as the following: 

str ing. substri ng(4, (string. length -2)) 

Instead, you can assign a negative number to the second parameter of 5 tr i ng.sl i ce( ) to indicate 
an offset from the end of the string: 

string. si i ce(4 , -2) 

The second parameter is optional. If you omit the second parameter, the returned value is a string 
from the starting offset to the end of the main string. 

249 



Part III: JavaScript Core Language Reference 



stringObjecLsUceQ 
Example 

With Listing 15-5, you can try several combinations of parameters with the string . si i ce( ) 
method (see Figure 15-3). A base string is provided (along with character measurements). Select from 
the different choices available for parameters, and study the outcome of the slice. 



FIGURE 15-3 



Lab for exploring the string. slice() method. 



{ String Slicing and Dicing, Part I - Mozilla Firefox 



Eile £dT yip* History Bookmarks Tools Hdr> 

String Slicing and Dicing, Part ] 

String sliced Method 

Text idnL fcir the melifcwis 
lEitccxociiLipt.ril'arj'FBfili 



B m IB 20 

Method Far»el«r. Rniln 

ittmfi.itiwO ( 1 2 » I 1-1 I » I ') iQcbMiiEBpfaita^ap 



Dare 



LISTING 15-5 



Slicing a String 



HTML: jsb-15-05.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Stri ng Slicing and Dicing, Part K/title> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 15-05 . j s "></scri pt> 

</head> 

<body> 

<hl>String Slicing and Dicing, Part K/hl> 



250 



Chapter 15: The String Object 



stringObject. s I i ce () 

<b>String sliceO Method</b> 

<form action="string-sl ice.php"> 

<P> 

< 1 a be 1 f or="source">Text used for the methods : </l abel > 

</p> 
<P> 

<textarea id="source" name="source" cols="60" rows="l"> 
Electroencephalograph</textarea> 
<pre> 

— "I— "I— "I— -I- 
5 10 15 20 

</pre> 

</p> 

<tabl e> 
<thead> 
<tr> 

<th>Method</th> 
<th>Parameters</th> 
<th>Resul ts</th> 
</tr> 
</thead> 
<tbody> 
<tr> 

<td>string.sl i ce ( )</td> 
<td>( 

<select id="parameterl" name="parameterl"> 



<opti on 


va" 


ue= 


0 


>0</opti on> 


<opti on 


va" 


ue= 


1 


>1</ opti on> 


<opti on 


va" 


ue= 


2 


>2</opti on> 


<opti on 


va" 


ue= 


3 


>3</ opti on> 


<opti on 


va" 


ue= 


5 


>5</ opti on> 



</sel ect> , 

<select i d="parameter2" name="paranieter2"> 

<opt ion>( None )</ opt ion> 

<option val ue="5">5</opti on> 

<option val ue=" 10">10</opti on> 

<option val ue=" - 1 ">- K/opti on> 

<option val ue=" -5">-5</opti on> 

<option value="-10">-10</option> 
</sel ect> 
)</td> 
<td> 

<input type="text" id="result" name="resul t" size="25" /> 

</td> 
</tr> 
</tbody> 
</table> 
</ f orm> 
</body> 
</html > 

continued 



251 



Part III: JavaScript Core Language Reference 



stringObject.s\ i ce () 

(continued) 



LISTING 15-5 



JavaScript: jsb-1505.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld ) 

{ 

// check for critical elements 

var oSource = document . getEl ementById( ' source ') ; 

var oParameterl = document . getEl ementByld (' parameterl ') ; 

var oParameter2 = document . getEl ementByld (' parameter2 ') ; 

var oResult = document . getEl ementById( ' resul t ') ; 

// if they al 1 exi st . . . 

if (oSource && oParameterl && oParameter2 && oResult) 
{ 

// apply behaviors 

addEvent ( oParameterl , 'change', showResul ts ) ; 
addEvent( oParameter2 , 'change', showResul ts ) ; 

} 

el se 
{ 

al ert ( ' Cri ti cal element not found'); 



// execute the method and display the result 

function showResul ts ( ) 

{ 

// get source text 

var oSource = document . getEl ementByld (' source ') ; 
var sSource = oSource . fi rstChi 1 d . nodeVal ue ; 

// get paramaters 

var oParameterl = document . getEl ementById( ' parameterl ') ; 

var iParameterl = parsel nt ( oParameterl . opti ons [oParameterl . sel ectedl ndex] . val ue ) ; 

var oParameter2 = document . getEl ementById( ' parameter2 ') ; 

var iParameter2 = parsel nt ( oParameter2 . opti ons [oParameter2 . sel ectedl ndex] . val ue ) ; 

// generate result & display it 

var oResult = document . getEl ementByld (' resul t ') ; 

if ( ! i Parameter2) 
{ 



252 



Chapter 15: The String Object 



i 



stringObject.spWtQ 

oResul t . val ue = sSource . si i ce ( i Parameterl ) ; 

} 

el se 
{ 

oResul t . val ue = sSource . si i ce ( i Parameterl , i Parameter2) ; 



Related Items: string . substr( ), string . substri ng( ) methods 

string .split(" del imiterCharacter" [, 1 imitlnteger]) 

Returns: Array of delimited items 

Compatibility: WinIE4+, MacIE4+, NN34-, Moz+, Safari+, Opera+, Chrome 4- 

The spl it( ) method is the functional opposite of the array. join( ) method (see Chapter 18, 
"The Array Object")- From the string object point of view, JavaScript splits a long string into pieces 
delimited by a specific character, and then creates a dense array with those pieces. You do not need to 
initialize the array via the new ArrayO constructor. Given the powers of array object methods, such 
as array. sort(), you may want to convert a series of string items to an array to take advantage of 
those powers. Also, if your goal is to divide a string into an array of single characters, you can still use 
the spl i t ( ) method, but specify an empty string as a parameter. For some older browsers, such as 
NN3 and IE4, only the first parameter is observed. 



In modern browsers, you can use a regular expression object for the first parameter, enhancing your 
power to find delimiters in strings. For example, consider the following string: 

var nameList = "Fred - 123-4567 , Jane - 234- 5678 , Steve - 345-6789"; 

To convert that string into an array of only the names takes a lot of parsing without regular expres- 
sions before you can even use str i ng . spl it(). However, with a regular expression as a parameter, 

var regexp = / - [\d-]+, ?\b/ ; 

var newArray = nameLi st . spl i t ( regexp ) ; 

// result = an array "Fred", "Jane", "Steve", "" 

the new array entries hold only the names, and not the phone numbers or punctuation. 

A second optional parameter, an integer value, allows you to specify a limit to the number of array 
elements generated by the method. 



Example 

Use The Evaluator (Chapter 4) to see how the s t r i n g . s p 1 i t ( ) method works. Begin by assigning 
a comma-delimited string to a variable: 

a = "Anderson , Smi th , Johnson , Washi ngton " 



253 



Part III: JavaScript Core Language Reference 



stringObjectsubstrQ 

Now split the string at comma positions so that the string pieces become items in an array, saved as b: 

b = a . s p 1 i t ( " , " ) 

To prove that the array contains four items, inspect the array's 1 ength property: 

b . 1 ength // resul t : 4 
Related Items: a rray . j oi n ( ) method 

string .substr(start [, length]) 

Returns: String 

Compatibility: WinIE4+, MacIE4+, NN4+, Moz4-, Safari 4-, Opera4-, Chrome4- 

The string. substr( ) method offers a variation of the string, substri ng( ) method that has 
been in the JavaScript language since the beginning. The distinction is that the S tr 7 ng . S ubs t r ( ) 
method's parameters specify the starting index and a number of characters to be included from that 
start point. In contrast, the string.substring( ) method parameters specify index points for the 
start and end characters within the main string. 

As with all string methods requiring an index value, the string. substr( ) first parameter is 
zero-based. If you do not specify a second parameter, the returned substring starts at the indexed 
point and extends to the end of the string. A second parameter value that exceeds the end point of 
the string means that the method returns a substring to the end of the string. 

Even though this method is newer than its partner, it is not part of the latest (Fifth) edition of the 
ECMA standard for the language. But because the method is so widely used, the standard does 
acknowledge it as an annex, so that other scripting contexts can implement the method, consistent 
with browser practice. 

Example 

Listing 15-6 lets you experiment with a variety of values to see how the string. substr( ) method 
works. 



LISTING 15-6 



Reading a Portion of a String 

HTML: jsb-1506.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Stri ng Slicing and Dicing, Part IK/title> 
<script type=" text /javascript" src="../jsb-global . js "></scn'pt> 
<script type="text/ j avascri pt" src="j sb- 15-06 . j s "></scri pt> 

</head> 

<body> 

<hl>String Slicing and Dicing, Part IK/hl> 



254 



Chapter 15: The String Object 



sfn'ngOb/ecf.substrO 

<h2>String substrO Method</h2> 

<form action="string-substr.php"> 

<P> 

< I a be I f or="source">Text used for the methods : </l abel > 

</p> 
<P> 

<textarea id="source" name="source" cols="60" rows="l"> 
Electroencephalograph</textarea> 
<pre> 

— "I— "I— "I— -I- 
5 10 15 20 

</pre> 

</p> 

<tabl e> 
<thead> 
<tr> 

<th>Method</th> 
<th>Parameters</th> 
<th>Resul ts</th> 
</tr> 
</thead> 
<tbody> 
<tr> 

<td>string.substr( )</td> 
<td>( 

<select id="parameterl" name="paranieterl"> 

<option val ue="0">0</opti on> 

<option val ue=" 1 ">K/opti on> 

<option val ue="2">2</opti on> 

<option val ue="3">3</opti on> 

<option val ue="5">5</opti on> 
</sel ect> , 

<select i d="parameter2" name="parameter2"> 
<option>(None)</option> 
<option val ue="5">5</opti on> 
<option val ue=" 10">10</opti on> 
<option val ue="20">20</opti on> 

</sel ect> 
)</td> 
<td> 

<input type="text" id="result" name="resul t" size="25" /> 

</td> 
</tr> 
</tbody> 
</table> 
</ f orm> 
</body> 
</html > 

continued 



255 



Part III: JavaScript Core Language Reference 



stringObject.substrQ 

(continued) 



LISTING 15-6 



JavaScript: jsb-1506.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// check for critical elements 

var oSource = document . getEl ementBy Id( ' source ') ; 

var oParameterl = document . getEl ementBy Id (' parameterl ') ; 

var oParameter2 = document . getEl ementBy Id (' parameter2 ') ; 

var oResult = document . getEl ementBy Id (' resul t ') ; 

// if they al 1 exi st . . . 

if (oSource && oParameterl && oParameter2 && oResult) 
{ 

// apply behaviors 

addEvent ( oParameterl , 'change', showResul ts ) ; 
addEvent( oParameter2 , 'change', showResul ts ) ; 

( 

el se 
{ 

al ert ( ' Cri ti cal element not found'); 



// execute the method and display the result 

function showResul ts ( ) 

{ 

// get source text 

var oSource = document . getEl ementBy Id (' source ') ; 
var sSource = oSource . fi rstChi 1 d . nodeVal ue ; 

// get paramaters 

var oParameterl = document . getEl ementBy Id( ' parameterl ') ; 

var iParameterl = parsel nt ( oParameterl . opti ons [oParameterl . sel ectedl ndex] . val ue ) 

var oParameter2 = document . getEl ementBy Id( ' parameter2 ') ; 

var iParameter2 = parsel nt ( oParameter2 . opti ons [oParameter2 . sel ectedl ndex] . val ue ) 

// generate result & display it 

var oResult = document . getEl ementBy Id (' resul t ') ; 

if { ! i Parameter2) 
{ 

oResul t . val ue = sSource . substr ( i Parameterl ) ; 

256 



Chapter 15: The String Object 



sfr/ngC%'eef.substring() 

} 

el se 
{ 

oResul t . val ue = sSource . substr ( i Parameterl , i Parameter2) ; 

) 

) 



Related Items: str ing. substri ng ( ) method 

string. substri ng( indexA[ , indexBJ) 

Returns: String of characters between index values indexA and indexB 

Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome + 

The str i ng. substri ng( ) method enables your scripts to extract a copy of a contiguous range of 
characters from any string. The parameters to this method are the starting and ending index values 
(the first character of the string object is index value 0) of the main string from which the excerpt 
should be taken. An important item to note is that the excerpt goes up to, but does not include, the 
character pointed to by the higher index value. 

It makes no difference which index value in the parameters is larger than the other: The method starts 
the excerpt from the lowest value and continues to (but does not include) the highest value. If both 
index values are the same, the method returns an empty string; and if you omit the second parameter, 
the end of the string is assumed to be the endpoint. 



Example 

Listing 15-7 lets you experiment with a variety of values to see how the str i ng . substri ng( ) 
method works. 



LISTING 15-7 



Reading a Portion of a String 

HTML: jsb-15-07.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Stri ng Slicing and Dicing, Part IIK/title> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 15-07 . j s "></scri pt> 

</head> 

<body> 

<hl>String Slicing and Dicing, Part IIK/hl> 
<h2>String substringO Method</h2> 

<form action="string-substring.php"> 

<P> 

<label f or="source">Text used for the methods : </l abel > 

continued 



257 



Part III: JavaScript Core Language Reference 



sfringOfe/ecf.substringO 



LISTING 15-7 



(continued) 



</p> 
<P> 

<textarea id="Textareal" 
Electroencephalograph</textarea> 
<pre> 



'source" cols="60" rows="l"> 



10 15 20 

</pre> 
</p> 



<tabl e> 
<thead> 
<tr> 

<th>Method</th> 
<th>Parameters</th> 
<th>Resul ts</th> 
</tr> 
</thead> 
<tbody> 
<tr> 

<td>string.substring{ )</td> 
<td>( 

<select id="parameterl" name="parameterl"> 



<opti on 


va" 


ue= 


0 


>0</opti on> 


<opti on 


va" 


ue= 


1 


>1</ opti on> 


<opti on 


va" 


ue= 


2 


>2</opti on> 


<opti on 


va" 


ue= 


3 


>3</ opti on> 


<opti on 


va" 


ue= 


5 


>5</ opti on> 



</sel ect> , 

<select i d="parameter2" name="paranieter2"> 
<option>( None )</ opt ion> 
<option val ue="3">3</opti on> 
<option value= 
<option value= 
</sel ect> 
)</td> 
<td> 

<input type="text' 
</td> 
</tr> 
</tbody> 
</table> 
</ form) 
</body> 
</html > 



'5">5</ opti on> 
'10">10</opti on> 



id="result" name="resul t" size="25" /> 



JavaScript: jsb-15-07.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 



258 



Chapter 15: The String Object 



sfr/ngC%'eef.substring() 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// check for critical elements 

var oSource = document . getEl ementBy Id( ' source ') ; 

var oParameterl = document . getEl ementBy Id (' parameterl ') ; 

var oParameter2 = document . getEl ementBy Id (' parameter2 ') ; 

var oResult = document . getEl ementBy Id( ' resul t ') ; 

// if they al I exi st . . . 

if (oSource && oParameterl && oParameter2 && oResult) 
< 

// apply behaviors 

addEvent ( oParameterl , 'change', showResul ts ) ; 
addEvent(oParameter2, 'change', showResul ts ) ; 

( 

el se 
{ 

al ert ( ' Cri ti cal element not found'); 



// execute the method and display the result 

function showResul ts ( ) 

{ 

// get source text 

var oSource = document . getEl ementBy Id (' source ') ; 
var sSource = oSource . fi rstChi I d . nodeVal ue ; 

// get paramaters 

var oParameterl = document . getEl ementBy Id( ' parameterl ') ; 

var iParameterl = parsel nt ( oParameterl . opti ons [oParameterl . sel ectedl ndex] . val ue ) ; 
var oParameter2 = document . getEl ementBy Id( ' parameter2 ') ; 

var iParameter2 = parsel nt ( oParameter2 . opti ons [oParameter2 . sel ectedl ndex] . val ue ) ; 

// generate result & display it 

var oResult = document . getEl ementBy Id (' resul t ') ; 

if ( ! i Parameter2) 
{ 

oResul t . val ue = sSource . substri ng( i Parameterl ) ; 

( 

el se 
{ 

oResul t . val ue = sSource . substri ng( i Parameterl , i Parameter2) ; 

I 



259 



Part III: JavaScript Core Language Reference 



sfringOfe/ecf.toLocaleLowerCaseO 

Related Items: string . substr( ), string . si iceC ) methods 

s tr 7 ng. to Local e Lowe rCase( ) 
s tr 7 ng. to Local eUpperCase( ) 

Returns: String 

Compatibility: WmIE5.5+, MacIE-, NN6+, Moz+, Safari-, Opera+, Chrome+ 

These two methods are variations on the standard methods for changing the case of a string. They 
take into account some language systems whose cases for a particular character don't necessarily map 
to the Latin alphabet character mappings. 

Related Items: string . toLowerCase ( ), str fng.tollpperCaseO methods 

s tr / ng. to Lowe rCase( ) 
stri ng. toUpperCase( ) 

Returns: The string in all lower- or uppercase, depending on which method you invoke 
Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome+ 

A great deal of what takes place on the Internet (and in JavaScript) is case-sensitive. URLs on some 
servers, for instance, are case-sensitive for directory names and filenames. 

These two methods, the simplest of the string methods, return a copy of a string converted to either 
all lowercase or all uppercase. Any mixed-case strings get converted to a uniform case. If you want to 
compare user input from a field against some coded string without worrying about matching case, you 
can convert copies of both strings to the same case for the comparison. 

Example 

You can use the toLowerCase( ) and tollpperCase( ) methods on literal strings, as follows: 

var newString = " HTTP : //www . Mozi 1 1 a . ORG" . toLowerCase ( ) ; 
// result = "http://www.mozilla.org" 

The methods are also helpful in comparing strings when case is not important, as follows: 

it ( guess . toUpperCase( ) == answer . toUpperCase( ) ) {...} 
// comparing strings without case sensitivity 

Note that these methods do not change the case of the strings themselves, but rather output modified 
copies, leaving the originals intact. 

Related Items: s tr ing. to Local eLowerCase ( ), str ing. to LocaleUpperCaseC ) methods 

string. toString( ) 
string. val ueOf ( ) 

Returns: String value 

Compatibility: WinIE4+, MacIE4+, NN4+, Moz-I-, Safari 4-, Opera 4-, Chrome4- 

260 



Chapter 15: The String Object 



Both of these methods return string values (as opposed to full-fledged string objects). If you have cre- 
ated a string obj ect via the n e w S t r i n g ( ) constructor, the type of that item is object. Therefore , 
if you want to examine more precisely what kind of value is held by the object, you can use the v a I - 
ueOf ( ) method to get the value and then examine it via the typeof operator. The toStri ng( ) 
method is present for this object primarily because a string object inherits the method from the root 
object of JavaScript. 



Example 

Use The Evaluator (Chapter 4) to test the val ueOf ( ) method. Enter the following statements into 
the top text box and examine the values that appear in the Results field: 

a = new Stri ng( "hel I o" ) 
typeof a 
b = a . val ueOf ( ) 
typeof b 

Because all other JavaScript core objects also have the val ueOf ( ) method, you can build generic 
functions that receive a variety of object types as parameters, and the script can branch its code based 
on the type of value that is stored in the object. 

Related Items: typeof operator (Chapter 22) 



String Utility Functions 

Figuring out how to apply the various string object methods to a string manipulation challenge is 
not always an easy task. The situation is only made worse if you need to support legacy or mobile 
browsers with limited JavaScript support. It's also difficult to anticipate every possible way you may 
need to massage strings in your scripts. But to help you get started, Listing 15-8 contains a fully 
backward-compatible library of string functions for inserting, deleting, and replacing chunks of text in 
a string. If your audience uses browsers capable of including external . j s library files, that would be 
an excellent way to make these functions available to your scripts. 



LISTING 15-8 



Utility String Handlers 

JavaScript: jsb-15-08.js 

// extract front part of string prior to searchString 

function getFront( sMai n , sSearch) 

{ 

iOffset = sMai n . i ndexOf ( sSearch ) ; 

if (iOffset == -1) 
{ 

return null; 

} 

el se 

continued 



261 



Part III: JavaScript Core Language Reference 



LISTING 15-8 



(continued) 



return sMai n . substri ng ( 0 , iOffset); 



// extract back end of string after searchString 

function getEnd ( sMai n , sSearch) 

{ 

iOffset = sMai n . i ndexOf ( sSearch ) ; 

if (iOffset == -1) 
{ 

return null; 

( 

el se 
{ 

return sMai n . substri ng ( i Of f set + sSearch . 1 ength , sMai n . 1 ength ) 



// insert insertString immediately before searchString 

function i nsertStri ng ( sMai n , sSearch, slnsert) 

{ 

var sFront = getFront( sMai n , sSearch); 
var sEnd = getEnd ( sMai n , sSearch); 

if (sFront == null || sEnd == null) 
! 

return null; 

} 

el se 
{ 

return sFront + slnsert + sSearch + sEnd; 



// remove sDelete from sMain 
function del eteStri ng ( sMai n , sDelete) 
{ 

return repl aceStri ng( sMai n , sDelete, ""); 



// replace sSearch with sReplace 

function repl aceStri ng ( sMai n , sSearch, sReplace) 

{ 



262 



Chapter 15: The String Object 



var sFront = getFront( sMai n , sSearch); 
var sEnd = getEncKsMai n , sSearch); 



f (sFront == null || sEnd == null) 

return null; 
I se 

return sFront + sReplace + sEnd; 



The first two functions extract the front or end components of strings, as needed, for some of 
the other functions in this suite. The final three functions are the core of these string-handling 
functions. If you plan to use these functions in your scripts, be sure to notice the dependence that 
some functions have on others. Including all five functions as a group ensures that they work as 
designed. 

A modern alternative to Listing 15-8 utilizes a combination of string and array methods to perform a 
global replace operation in a one-statement function: 

function repl aceStri ng( sMai n , sSearch, sReplace) 
{ 

return sMain.split(sSearch).join(sReplace); 

} 

Going one step further, you can create a custom method to use with all string values or objects in 
your scripts. Simply let the following statement execute as the page loads: 

St r i ng . prototype . repl aceStri ng = function repl aceStri ng( sMai n , 
sSearch, sReplace) 

{ 

return sMain.split(sSearch).join(sReplace); 

} 

Then, invoke this method on any string value in other scripts on the page, as in: 

myString = myStri ng . repl aceStri ng( " CD ", " MP3 "); 

(Note that global search and replace can also be accomplished using regular expressions; see Chapter 
45.) 



HTML markup methods 

Now we come to the other group of string object methods that effectively enclose text in HTML ele- 
ments. None of these methods are part of the ECMAScript Fifth Edition standard; their persistence in 
JavaScript implementations is clearly in support of ancient scripts. Modern web pages use stylesheets 
to apply cosmetic formatting to elements, and DOM methods to insert new nodes. 



263 



Part III: JavaScript Core Language Reference 



str i ng.anchor( " anchorName" ) 


string 


n nk( 1 ocati onOrURL) 


string. b~\ i nk( ) 


string 


big() 


str f ng. bol d ( ) 


string 


smal 1 ( ) 


stri ng.fi xed ( ) 


string 


stri ke ( ) 


str ing. font col or ( co 1 or Va 1 ue) 


string 


sub( ) 


stri ng. fonts i ze( integer 1 to7) 


string 


sup( ) 


string . i tal i cs ( ) 



First examine the methods that don't require any parameters. You probably see a pattern: All of these 
methods are font-style attributes that have settings of on or off. To turn on these attributes in an 
HTML document, you surround the text in the appropriate tag pairs, such as <b> . . . </b> for bold- 
face text. These methods take the string object, attach those tags, and return the resulting text, which 
is ready to be put into any HTML that your scripts are building. Therefore, the expression 

"Good morni ng ! " . bol d( ) 

evaluates to 

<b>Good morning!</b> 

Listing 15-9 shows an example of applying these string methods to text on the page. (Internet 
Explorer, Chrome, and Safari do not support the <bl i nk> element, so while they execute the 
Stri ng .bl i nk( ) method, there is no resulting blink in the display.) 



LISTING 15-9 



Using Simple String Methods 

HTML: jsb-15-09.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>HTML by JavaScri pt</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 15-09 . j s "></scri pt> 

</head> 

<body> 

<hl>HTML by JavaScri pt</hl> 



<ul id= 


'tag 


- 1 i s t " > 


<1 i 


id=' 


anchor ">anchor</l i> 


<1 i 


id=' 


big">big</l i> 


<1 i 


id=' 


bl i n k " > b 1 ink</l i> 


<1 i 


id=' 


bold">bold</l i> 


<1 i 


id=' 


fixed">fixed</l i> 


<1 i 


id=' 


fontcolor">fontcolor</li> 



264 



Chapter 15: The String Object 



<l i id="fontsize">fontsize</l i> 
<li i d=" i tal i cs ">i tal i cs</l i > 
<li id="l i n k " > I ink</l i> 
<li i d="smal I ">smal I </l i > 
<li i d="stri ke">stri ke</l i > 
<li>sub H<span i d="sub">2</span>0</l i > 
<li>sup E=mc<span i d="sup">2</span></l i > 
</ul > 

<form action="html -by-javascript.php"> 
<P> 

<button id="apply-markup">Apply Markup</button> 
</p> 
</ f orm> 
</body> 
</html > 



JavaScript: jsb-1509.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 



f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// check for button 

var oButton = document . getEl ementBy Id( ' appl y-markup ') ; 



// if it exi sts . . . 

if (oButton) 

{ 

// apply behavior 

addEvent ( oButton , 'click', applyMarkup) ; 

} 



// apply markup to text elements 

function applyMarkup(evt) 

{ 

// consolidate event handling 

if (!evt) evt = wi ndow . event ; 



var oList = document . getEl ementBy Id (' tag- 1 i st ') ; 
var aElements = oLi st . getEl ementsByTagName ('*') ; 

for (var i = 0; i < aEl ements . I ength ; i++) 
{ 

// get this element's id & text value 
s Id = aEl ements [ i ] . i d ; 

continued 



265 



Part III: JavaScript Core Language Reference 



LISTING 15-9 



(continued) 



//var sText = aEl ements [ i ]. fi rstChi 1 d . nodeVal ue ; 
var sText = aEl ements [ i ]. i nnerHTML ; 



switch (sld) 



case 
case 
case 
case 
case 
case 
case 
case 
case 
case 
case 
case 
case 



anchor': sText = sText . anchor( ' anchor-name ') ; break; 

big': sText = sText.bigO; break; 

blink': sText = sText . bl i nk( ) ; break; 

bold': sText = sText . bol d ( ) ; break; 

fixed': sText = sText . f i xed( ) ; break; 

fontcolor': sText = sText . f ontcol or( ' red ' ) ; break; 

fontsize': sText = sText . f ontsi ze ( 7 ) ; break; 

italics': sText = sText . i tal i cs ( ) ; break; 

link': sText = sText . 1 i n k ( ' http : / /exampl e . com/ ' ) ; break; 

small': sfext = sText . smal 1 ( ) ; break; 

strike': sText = sText . stri ke( ) ; break; 

sub': sText = sText.subO; break; 

sup': sText = sText.supO; break; 



default: continue; 



// replace the element's contents with the marked-up text 

aEl ements[i ]. i nnerHTML = sText; 

} 

alert('Here is the modified markup:\n' + o Li st . i nnerHTML) ; 



// cancel form submission 

// W3C DOM method (hide from IE) 

if { evt . preventDef aul t ) evt . preventDef aul t ( ) ; 
// IE method 
return false; 



string, fontsi ze( ) and string, fontcol or( ) affect the font characteristics of strings dis- 
played in the HTML page. The parameters for these items are pretty straightforward — an integer 
between 1 and 7, corresponding to the seven browser font sizes, and a color value (as either a hex- 
adecimal triplet or color constant name) for the designated text. 

The final two string methods let you create an anchor and a link out of a string. The 
String, anchor ( ) method uses its parameter to create a name for the anchor. Thus, the 
following expression 

"Table of Contents ".anchor(" toe") 
evaluates to 

<a name="toc">Tabl e of Contents</a> 



266 



Chapter 15: The String Object 



In a similar fashion, the String. 1 i nk( ) method expects a valid location or URL as its parameter, 
creating a genuine HTML link out of the string: 

"Back to Home" . 1 i nk( " i ndex . html " ) 
This evaluates to the following: 

<a h ref=" i ndex . html " >Back to Home</a> 

The primary reason that we rarely, if ever, use these methods in contemporary web site scripting is 
that we endeavor to separate development layers — in this case, HTML structure from CSS presen- 
tation and from JavaScript behavior. The more we keep these layers apart, the more modular and 
efficient development, debugging, and modification will be. For example, if all the font size and color 
details are specified in the style sheet, and not hard-coded in to HTML or JavaScript, then the appear- 
ance of the text on a page can be changed independently of the page's markup and behavior, and by 
different personnel with different skill sets. Similarly, it makes sense to keep markup in the HTML 
document and to enable JavaScript to operate on that markup, but not to stipulate it unless absolutely 
necessaiy. 

Changing the cosmetic appearance of a page by changing its markup is a very "90s" thing to do. It 
relies on the default styling of the browser for a given tag, instead of taking responsibility for styling 
in one's own stylesheet. A modern script will change the appearance of an element by assigning an i d 
or cl assName, and letting the stylesheet determine how that will be presented. 



URL String Encoding and Decoding 

When browsers and servers communicate, some non-alphanumeric characters that we take for granted 
(such as spaces) cannot make the journey in their native form. Only a narrower set of letters, num- 
bers, and punctuation is allowed. To accommodate the rest, the characters must be encoded with a 
special symbol (%) and their hexadecimal ASCII values. For example, the space character is hex 20 
(ASCII decimal 32). When encoded, it looks like %20. You may have seen this symbol in browser 
history lists or URLs. 

JavaScript includes two functions, encodeURIComponent( ) and decodeURIComponent( ), that 
offer instant conversion of whole strings. To convert a plain string to one with these escape codes, use 
the escape function, as in 

encodellRIComponent ( "Howdy Pardner"); // result = "Howdy%20Pardner" 
The decodeURI Component ( ) function converts the escape codes into human-readable form. 

Cross-Reference 

Both of these functions are covered in Chapter 24, "Global Functions and Statements." ■ 



267 



The Math, Numher, 
and Boolean Objects 



CHAPTER 




The introduction to data types and values in Chapter 8's tutorial scratched 
the surface of JavaScript's numeric and Boolean powers. In this chapter, 
you look more closely at JavaScript's way of working with numbers and 
Boolean data. 

Math often frightens away budding programmers. As you've seen so far in 
this book, however, you don't really have to be a math genius to program 
in JavaScript. The powers described in this chapter are here when you need 
them — if you need them. So if math is not your strong suit, don't freak out 
over the terminology here. 

An important point to remember about the objects described in this chapter is 
that (like string values and string objects) numbers and Booleans are both values 
and objects. Fortunately for script writers, the differentiation is rarely, if ever, a 
factor, unless you get into some very sophisticated programming. To those who 
actually write the JavaScript interpreters inside the browsers we use, the distinc- 
tions are vital. 

For most scnpters, the information about numeric data types and conversions, as 
well as the Math object, are important to know. 



IN THIS CHAPTER 



Advanced math operations 

Number base conversions 

Working with integers and 
floating-point numbers 



Numbers in JavaScript 

More powerful programming languages have many different kinds of num- 
bers, each related to the amount of memory the number occupies in the 
computer. Managing all these different types may be fun for some, but 
it gets in the way of quick scripting. A JavaScript number has only two 
possibilities. It can be an integer or a floating-point value. An integer is 
any whole number within a humongous range that does not have any frac- 
tional part. Integers never contain a decimal point in their representation. 
Floating-point numbers in JavaScript spread across the same range, but they 
are represented with a decimal point and some fractional value. If you are 
an experienced programmer, refer to the discussion about the Number 



269 



Part III: JavaScript Core Language Reference 



object later in this chapter to see how the JavaScript number type lines up with the numeric data types 
you use in other programming environments. 



Integers and floating-point numbers 

Deep inside a computer, the microprocessor has an easier time performing math on integer values 
compared to any number with a decimal value tacked onto it. The microprocessor must go through 
extra work to add even two such floating-point numbers. We, as scnpters, are unfortunately saddled 
with this historical baggage and must be conscious of the type of number used in certain calculations. 

Most internal values generated by JavaScript, such as index values and 1 ength properties, consist 
of integers. Floating-point numbers usually come into play as the result of the division of numeric 
values, special values such as pi, and human-entered values such as dollars and cents. Fortunately, 
JavaScript is forgiving if you tiy to perform math operations on mixed numeric data types. Notice 
how the following examples resolve to the appropriate data type: 

3 + 4 = 7 // integer result 

3 + 4.1 = 7.1 // floating-point result 

3.9 + 4.1 = 8 // integer result 

Of the three examples, perhaps only the last result is unexpected. When two floating-point numbers 
yield a whole number, the result is rendered as an integer. 

When dealing with floating-point numbers, be aware that not all browser versions return the precise 
same value down to the last digit to the right of the decimal. For example, the following table shows 
the result of 8/9 as calculated by various scriptable browsers, and converted for string display: 



NN3 & NN4 .8888888888888888 


NN6+/Moz+/Safari+/Opera+/Chrome+ 


0.8888888888888888 


WinIE3 


0.888888888888889 


WmIE4+ 


0.8888888888888888 



Clearly, from this display, you don't want to use floating-point math in JavaScript browsers to plan 
space flight trajectories or other highly accurate mission-critical calculations. Even for everyday math, 
however, you need to be cognizant of floating-point errors that accrue in PC arithmetic. 

In Navigator, JavaScript relies on the operating system's floating-point math for its own math. Operat- 
ing systems that offer accuracy to as many places to the right of the decimal as JavaScript displays are 
exceedingly rare. As you can detect from the preceding table, modern browsers agree about how many 
digits to display and how to perform internal rounding for this display. That's good for the math, but 
not particularly helpful when you need to display numbers in a specific format. 

Until you get to IE5.5, Mozilla-based browsers, and other W3C-compatible browsers, JavaScript does 
not offer built-in facilities for formatting the results of floating-point arithmetic. (For modern browsers, 
see the Number object later in this chapter for formatting methods.) Listing 16-1 demonstrates a 
generic formatting routine for positive values, plus a specific call that turns a value into a dollar value. 
Remove the comments, and the routine is fairly compact. 



270 



Chapter 16: The Math, Number, and Boolean Objects 



Cross-Reference 

The function to assign event handlers throughout the code in this chapter, and much of the book, is 
addEvent( ), a cross-browser event handler explained in detail in Chapter 32, "Event Objects." ■ 



LISTING 16-1 



A Generic Number-Formatting Routine 

HTML: jsb-16-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Number Formatti ng</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 16-01 . j s "></scri pt> 

</head> 

<body> 

<hl>How to Make Money</hl> 
<f orm> 

<P> 

< 1 a be 1 f or="entry ">Enter a positive floating point value or arithmetic 
expression to be converted to a currency format : </l abel > 

</p> 
<P> 

<input type="text" id="entry" name="entry" value="l/3"> 

<input type="button" id="dollars" value="> Dollars and Cents >"> 

<input type="text" id="result" name="resul t"> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-16-01.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to critical elements 

var oButton = document . getEl ementBy Id (' dol 1 ars ') ; 
var oEntry = document . getEl ementBy Id (' entry ') ; 
var oResult = document . getEl ementBy Id (' resul t ') ; 

// if they al 1 exi st . . . 

if (oButton && oEntry && oResult) 

continued 



271 



Part III: JavaScript Core Language Reference 



LISTING 16-1 



(continued) 



II apply behavior to button 
oButton .onclick = 

functionO { oResul t . val ue = dol 1 ari ze ( oEntry . val ue ) ; ) 



// turn incoming expression into a dollar value 
function dol 1 ari ze(expr) 



return "$" + format(expr,2) ; 



// generic positive number decimal formatting function 

function format(expr, decplaces) 

{ 

// evaluate the incoming expression 
var val = eval (expr) ; 

// raise the value by power of 10 times the number of decimal places; 

// round to an integer; convert to string 

var str = "" + Math . round ( val * Math.powdO, decplaces)); 

// pad small value strings with zeros to the left of rounded number 

while (str. length <= decplaces) 

{ 

str = "0" + str; 



// establish location of decimal point 
var decpoint = str. length - decplaces; 



// assemble final 
// (a) the string 
// (b) the decimal 
// (c) the balance 
return str 



result from: 

up to the position of the decimal point; 
point; and 
Da I ance of the string 
.substringCO, decpoint) 



Return finished product. 
"." + str . substri ng ( decpoi nt , 



str . 1 ength ) ; 



This routine may seem like a great deal of work, but it's essential if your application relies on 
floating-point values and specific formatting for all browsers. 

Note 

The global eval ( ) method used in this example is not a terrific choice for production work. Because eval ( ) 
faithfully interprets all JavaScript expressions, it lays bare all the details of the script, its object and variable 
values, and the DOM, for the savvy visitor to peruse and act upon. The JavaScript language has deliberately 
been constrained to prevent security breaches on the client computer, but XMLHttpRequest gives access to 
the server. It's not appropriate to give strangers an open and unfiltered eval ( ) input. ■ 



272 



Chapter 16: The Math, Number, and Boolean Objects 



You can also enter floating-point numbers with exponents. An exponent is signified by the letter e 
(upper- or lowercase), followed by a sign (+ or -) and the exponent value. Here are examples of 
floating-point values expressed as exponents: 

le6 // 1,000,000 (the "+" symbol is optional on positive exponents) 
le-4 // 0.0001 (plus some error further to the right of the decimal) 
-4e-3 // -0.004 

For values between le-5 and lel5, JavaScript renders numbers without exponents (although you can 
force a number to display in exponential notation in modern browsers). All other values outside these 
boundaries return with exponential notation in all browsers. 



Hexadecimal and octal integers 

JavaScript enables you to work with values in decimal (base- 10), hexadecimal (base- 16), and 
octal (base-8) formats. You have only a few rules to follow when dealing with any of these 
values. 

Decimal values cannot begin with a leading 0. Therefore, if your page asks users to enter decimal val- 
ues that begin with a 0, your script must strip those zeros from the input string, or use the number 
parsing global functions (described in the next section), before performing any math on the values. 

Hexadecimal integer values are expressed with a leading Ox or OX. (That's a zero, not the letter o.) 
The A through F values can appear in upper- or lowercase, as you prefer. Here are some hex values: 

0X2B 
OXla 
Oxcc 

Don't confuse the hex values used in arithmetic with the hexadecimal values used in color property 
specifications for web documents. Those values are expressed in a special hexadecimal triplet format, 
which begins with a Crosshatch symbol followed by the three hex values bunched together (such as 
#c0c0c0). 

Octal values are represented by a leading 0 followed by any digits between 0 and 7. Octal values con- 
sist only of integers. 

You are free to mix and match base values in arithmetic expressions, but JavaScript renders all results 
in decimal form. For conversions to other number bases, you have to employ a user-defined function 
in your script. Listing 16-2, for example, is a function that converts any decimal value from 0 to 255 
into a JavaScript hexadecimal value. 



LISTING 16-2 



Decimal-to-Hexadecimal Converter Function 

function toHex(dec) 

{ 

hexChars = " 0 1 2345 67 89ABC D E F " ; 

if (dec > 255) 

1 



continued 

273 



Part III: JavaScript Core Language Reference 




(continued) 



return null; 

} 

var i = dec % 16; 

var j = (dec - i) / 16; 

resul t = "OX" ; 

result += hexCha rs . cha rAt ( j ) ; 
result += hexCha rs . cha rAt ( i ) ; 
return result; 



The toHex( ) conversion function assumes that the value passed to the function is a decimal integer. 
If you simply need a hexadecimal representation of a number in string format, see the toStri ng( ) 
method in Chapter 15, "The String Object." 

Converting strings to numbers 

What is missing so far from this discussion is a way to convert a number represented as a string to a 
number with which the JavaScript arithmetic operators can work. Before you get too concerned about 
this, be aware that most JavaScript operators and math methods gladly accept string representations 
of numbers and handle them without complaint. You will run into data type incompatibilities most 
frequently when trying to accomplish addition with the + operator (which is also the string concate- 
nation operator). Also know that if you perform math operations on values retrieved from form text 
boxes, those object val ue properties are strings. Therefore, in many cases, you need to convert those 
string values to a number type for math operations. 

Conversion to numbers requires one of two JavaScript functions: 

parselnt( string [, radix]) 
parseFl oat( string I, radix!) 

These functions are inspired by the Java language. The term parsing has many implied meanings in 
programming. One meaning is the same as extracting. The parselnt( ) function returns whatever 
integer value it can extract from the string passed to it; the parseFl oat() function returns the 
floating-point number that can be extracted from the string. Here are some examples and their result- 



pa rs e Fl oat (" f red " ) // result = NaN (Not a Number) 

Because the parseFl oat() function can also work with an integer and return an integer value, you 
may prefer using this function in scripts that have to deal with either kind of number, depending on 
the string entered into a text field by a user. 

An optional second parameter to both functions enables you to specify the base of 
the number represented by the string. This comes in handy particularly when you need a dec- 
imal number from a string that starts with one or more zeros. Normally, the leading zero indicates an 



1 



ing values: 



parselnt("42") 
parselnt("42.33") 
parseFl oat("42. 33") 
parseFl oat( "42" ) 



// result 

// result 

// result 

// result 



42 
42 



42.33 

42 



274 



Chapter 16: The Math, Number, and Boolean Objects 



octal value. But if you force the conversion to recognize the string value as a decimal, it is converted 
the way you expect: 

parselnt( "010" ) // resul t = 8 

parselnt( "010" , 10) // result = 10 

parselnt( " F2" ) // result = NaN 

parselnt( "F2" , 16) // result = 242 

Use these functions wherever you need the integer or floating-point value. For example: 

var result = 3 + parselnt( "3" ) ; // result = 6 
var ageVal = pa rse I nt ( document . forms [0] . age . val ue ) ; 

The latter technique ensures that the string value of this property is converted to a number, 
although you should do more data validation — see Chapter 46, "Data-Entry Validation" (on the 
CD-ROM) — before trying any math on a user-entered value. 

Both the p a r s e I n t ( ) and parseFloat() methods start working on the first character of a string 
and continue until there are no more numbers or decimal characters. That's why you can use them 
on strings — such as the one returned by the navi gator. appVers ion property (for example, 
6.0 (Windows; en-US)) — to obtain just the leading, numeric part of the string. If the string 
does not begin with an acceptable character, the methods return NaN (not a number). 



Converting numbers to strings 

If you attempt to pass a numeric data type value to many of the string methods discussed in Chapter 
15, JavaScript complains. Therefore, you should convert any number to a string before, for example, 
you find out how many digits make up a number. 

Several ways exist to force conversion from any numeric value to a string. The old-fashioned way is to 
precede the number with an empty string and the concatenation operator. For example, assume that 
a variable named dollars contains the integer value of 2500. To use the string object's length 
property (discussed later in this chapter) to find out how many digits the number has, use this con- 
struction: 



("" + dollars). length // result = 4 



The parentheses force JavaScript to evaluate the concatenation before attempting to extract the 
length property. 

A more elegant way is to use the toStri ng( ) method. Construct such statements as you would to 
invoke any object's method. For example, to convert the dollars variable value to a string, use this 
statement: 



dollars. toStringO // result = "2500" 

This method has one added power in modern browsers: You can specify a number base for the 
string representation of the number. Called the radix, the base number is added as a parameter to 
the method name. Here is an example of creating a numeric value for conversion to its hexadecimal 
equivalent as a string: 

var x = 30 ; 

var y = x . toStri ng( 16 ) ; // result = "le" 



275 



Part III: JavaScript Core Language Reference 



mathObject 

Use a parameter of 2 for binary results and 8 for octal. The default is base 10. Be careful not to con- 
fuse these conversions with true numeric conversions. You cannot use results from the toStri ng( ) 
method as numeric operands in other statements. 

Finally, in IE5.5+, Mozilla-based browsers, and other W3C browsers, three additional methods of 
the Number object — toExponential ( ), toFixed( ), and toPrecisionO — return string ver- 
sions of numbers formatted according to the rules and parameters passed to the methods. We describe 
these in detail later in this chapter. 

When a number isn't a number 

In a couple of examples in the previous section, you probably noticed that the result of some opera- 
tions was a value named NaN. That value is not a string, but rather a special value that stands for Not 
a Number. For example, if you try to convert the string "joe" to an integer with parseFl oat( ), 
the function cannot possibly complete the operation. It reports back that the source string, when con- 
verted, is not a number. 

When you design an application that requests user input or retrieves data from a server-side database, 
you cannot be guaranteed that a value you need to be numeric is, or can be converted to, a number. 
If that's the case, you need to see if the value is a number before performing a math operation on it. 
JavaScript provides a special global function, isNaN( ), that enables you to test the "numberness" of 
a value. The function returns true if the value is not a number and f al se if it is a number. For 
example, you can examine a form field that should be a number: 

var ageEntry = pa rsel nt ( document . forms [0] . age . val ue ) ; 
if ( i sNaN ( ageEntry ) ) 
{ 

alert("Try entering your age again."); 

) 



Math Object 

Whenever you need to perform math that is more demanding than simple arithmetic, look through 
the list of Math object methods for the solution. 

Syntax 

Accessing Math object properties and methods: 
Math . property 

Math . method ( va lue [, value}) 
Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome+ 

About this object 

In addition to the typical arithmetic operations (covered in detail in Chapter 22, "JavaScript Opera- 
tors"), JavaScript includes more advanced mathematical powers that you can access in a way that may 
seem odd to you if you have not programmed in true object-oriented environments before. Although 
most arithmetic takes place on the fly (such as var resul t = 2 + 2), the rest requires use of the 



276 



Chapter 16: The Math, Number, and Boolean Objects 



mathObject 

JavaScript internal Math object (with a capital "M"). The Math object brings with it several proper- 
ties (which behave like some other languages' constants) and many methods (which behave like some 
other languages' math functions). 

The way you use the Math object in statements is the same way you use any JavaScript object: You 
create a reference beginning with the Math object's name, a period, and the name of the property or 
method you need: 

Math . property | methodilparameter] . . . [, parameter^) 

Property references return built-in values, such as pi. Method references require one or more values to 
be sent as parameters of the method. Every method returns a result. 

Properties 

JavaScript Math object properties represent a number of valuable constant values in math. Table 16-1 
shows you those methods and their values, as displayed to 16 decimal places. 

Because these property expressions return their constant values, you use them in your regular arith- 
metic expressions. For example, to obtain the circumference of a circle whose diameter is in variable 
d, employ this statement: 

circumference = d * Math. PI; 

Perhaps the most common mistakes scripters make with these properties are failing to capitalize the 
Math object name and observing the case-sensitivity of property names. 



TABLE 16-1 



JavaScript Math Properties 


Property 


Value 


Description 


Math. E 


2.718281828459045091 


Euler's constant 


Math. LN2 


0.6931471805599452862 


Natural log of 2 


Math. LN10 


2.302585092994045901 


Natural log of 10 


Math. L0G2E 


1.442695040888963387 


Log base-2 of E 


Math. L0G10E 


0.4342944819032518167 


Log base- 10 of E 


Math. PI 


3.141592653589793116 


Tt 


Math . SQRT1_2 


0.7071067811865475727 


Square root of 0.5 


Math . SQRT2 


1 .414213562373095145 


Square root of 2 



Methods 

Methods make up the balance of JavaScript Math object powers. With the exception of the 
Math . random( ) method, all Math object methods take one or more values as parameters. Typical 



277 



Part III: JavaScript Core Language Reference 



mathObject 

trigonometric methods operate on the single values passed as parameters; others determine which of 
the numbers passed along are the highest or lowest of the group. The Math.randomO method takes 
no parameters, but returns a randomized, floating-point value between 0 and 1. Table 16-2 lists all 
the Math object methods with their syntax, and descriptions of the values they return. 



TABLE 16-2 



Math Object Methods 


Method Syntax 






Returns 


Math 


, abs (val ) 






Absolute value of val 


Math 


, acos (val ) 






Arc cosine (in radians) of val 


Math 


. asi n (va 1 ) 






Arc sine (in radians) of val 


Math 


, atan ( val ) 






Arc tangent (in radians) of val 


Math 


. atan2 ( vail 


, va!2) 




Angle of polar coordinates x and y 


Math 


, cei 1 (val ) 






Next integer greater than or equal to val 


Math 


, cos (val ) 






Cosine of val 


Math 


.exp(val ) 






Euler's constant to the power of val 


Math 


, f 1 oor (val ) 






Next integer less than or equal to val 


Math 


. 1 og ( va 1 ) 






Natural logarithm (base e) of val 


Math 


. max (vail, 


va!2) 




The greater of vail or val2 


Math 


. mi n ( va 11 , 


val2) 




The lesser of vail or val2 


Math 


, pow (vail, 


va!2) 




Vail to the power of val2 


Math 


, random( ) 






Random number between 0 and 1 


Math 


, round (val ) 






N+1 when val >= n.5; otherwise N 


Math 


, sin (val ) 






Sine (in radians) of val 


Math 


.sqrt(val ) 






Square root of val 


Math 


. tan (va 1 ) 






Tangent (in radians) of val 



Although HTML may not exactly be a graphic artist's dream environment, it is possible to use 
JavaScript trig functions to obtain a series of values for HTML-generated charting. Since the advent of 
positionable elements, scripters have been able to apply their knowledge of using these functions to 
define fancy trajectories for flying elements. For scripters who are not trained in programming, math 
is often a major stumbling block. But as you've seen so far, you can accomplish a great deal with 
JavaScript by using simple arithmetic and a little bit of logic — leaving the heavy-duty math for those 
who love it. 



278 



Chapter 16: The Math, Number, and Boolean Objects 



mathObject 

Creating random numbers 

One of the handiest methods in the Math object is Math, rand om( ), which returns a random 
floating-point value between 0 and 1. If you design a script to act like a card game, you need 
random integers between 1 and 52; for dice, the range is 1 to 6 per die. To generate a random 
integer between zero and any top value (n), use the following formula (where n is the top 
number): 

Math . f 1 oor(Math . random( ) * n) 

This produces integers between 0 and n-1. To produce the spread between 1 and n, either add 1 or 
change f 1 o o r ( ) to c e i 1 ( ) : 

Math . f 1 oor(Math . random( ) * n) + 1 
Math . cei 1 ( Math . random( ) * n) 

To generate random numbers within a range that starts somewhere other than zero, use this formula: 

Math . f 1 oor(Math . random( ) * ( n - m + 1)) + m 

Here, m is the lowest possible integer value of the range, and n equals the top number of the range. 
For the dice game, the formula for each die is 

newDieValue = Math . f 1 oor(Math . random( ) * 6) + 1; 



Math object shortcut 

In Chapter 21, "Control Structures and Exception Handling," you see details about a JavaScript con- 
struction that enables you to simplify the way you address multiple Math object properties and meth- 
ods in statements. The trick is to use the with statement. 

In a nutshell, the with statement tells JavaScript that the next group of statements (inside the braces) 
refers to a particular object. In the case of the Math object, the basic construction looks like this: 

with (Math) 
{ 

/ / statements 

) 

For all intervening statements, you can omit the specific references to the Math object. Compare the 
long reference way of calculating the area of a circle (with a radius of six units) 

result = Math.pow(6,2) * Math. PI; 
to the shortcut reference way: 

with (Math) 
{ 

result = pow(6,2) * PI; 

) 

Though the latter occupies more lines of code, the object references are shorter and more natural to 
read. For a longer series of calculations involving Math object properties and methods, the with 



279 



Part III: JavaScript Core Language Reference 



numberObject 

construction saves keystrokes and reduces the likelihood of a case-sensitive mistake with the object 
name in a reference. You can also include other full-object references within the with construction; 
JavaScript attempts to attach the object name only to those references lacking an object name. On the 
downside, the with construction is not particularly efficient in JavaScript because it must perform a 
lot of internal tracking in order to work. So, it's best not to use it in loops that iterate a large number 
of times. 



Number Object 




Properties 


Methods 


constructor 


toExponenti al ( ) 


MAX_VALUE 


toFi xed( ) 


MIN_VALUE 


toLocal eStri ng( ) 


NaN 


toStri ng( ) 


N EGAT I V E_I N F I N I TY 


toPreci si on( ) 


POSITIVE_INFINITY 


val ueOf ( ) 


prototype 



Syntax 

Creating a Number object: 

var val = new Number ( number) ; 
Accessing number and Number object properties and methods: 

number . property | methodiLpa rameters^l) 
Number . property | method( [parameters] ) 

Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari-E, Opera+, Chrome+ 



About this object 

The Number object is rarely used because (for the most part) JavaScript satisfies day-to-day numeric 
needs with a plain number value. But the Number object contains some information and power of 
value to serious programmers. 

First on the docket are properties that define the ranges for numbers in the language. The largest 
number is 1.79E+308; the smallest number is 2.22E-308. Any number larger than the maximum is 
POSITIVE_INFINITY; any number smaller than the minimum is N EGAT I V E_I N F I N I TY. Rarely 
will you accidentally encounter these values. 



280 



Chapter 16: The Math, Number, and Boolean Objects 



numberObject. NaN 

More to the point of a JavaScript object, however, is the prototype property. Chapter 15 shows 
how to add a method to a string object's prototype, such that every newly created object 
contains that method. The same goes for the Number . prototype property. If you have a need to 
add common functionality to every number object, this is where to do it. This prototype facility is 
unique to full-fledged number objects and does not apply to plain number values. For experienced 
programmers who care about such matters, JavaScript number objects and values are defined 
internally as IEEE double-precision 64-bit values. 



Properties 

constructor 

(See stri ng . constructor in Chapter 15) 

MAX_VALUE 

MIN_VALUE 

NEGATI VE_INFI NITY 

POSITIVE_INFINITY 

Value: Number Read-Only 

Compatibility: WinIE4+, MacIE44-, NN34-, Moz4-, Safari4-, Opera4-, Chrome + 

The Number . MAX_VALUE and Number . MI N_VALUE properties belong to the static Number object. 
They represent constants for the largest and smallest possible positive numbers that JavaScript (and 
ECMAScript) can work with. Their actual values are 1.7976931348623157 oo 10 308 , and 5 oo 10" 324 , 
respectively. A number that falls outside the range of allowable numbers is equal to the constant 
Number. POSITIVES NFI NITY or Number . N EGATI VE_I N FI N ITY. 



Example 

Enter each of the four Number object expressions into the top text field of The Evaluator (Chapter 4, 
"Javascript Essentials") to see how the browser reports each value. 



Number . MAX_VALUE 
Number. MIN_VALUE 
Number. N EGATI V E_I N FI N ITY 
Number. POSITI VE_I N FI N ITY 

Related Items: N a N property; i s N a N ( ) global function 



NaN 

Value: NaN Read-Only 

Compatibility: WinIE44-, MacIE44-, NN34-, MozT-, SafariT-, OperaT-, Chrome + 

The NaN property is a constant that JavaScript uses to report when a number-related function or 
method attempts to work on a value other than a number, or when the result is something other 
than a number. You encounter the NaN value, most commonly as the result of the parselnt( ) and 
parseFloatO functions, whenever a string undergoing conversion to a number lacks a numeral as 
the first character. Use the i s N a N ( ) global function to see if a value is an NaN value. 



281 



Part III: JavaScript Core Language Reference 



numberObjeclprototype 
Example 

See the discussion of the i s N a N ( ) function in Chapter 24. 
Related Items: i s N a N ( ) global function 

prototype 

(See St r i ng . prototype in Chapter 15) 

Methods 

number . to Exponent i al ( fracti onDigits) 
number . toFi xed( fracti onDi gi ts) 
number . toPreci si on( preci si onDi gi ts) 

Returns: String 

Compatibility: WmIE5.5+, MacIE-, NN6+, Moz+, Safari+, Opera+, Chrome+ 

These three methods let scripts control the formatting of numbers for display as string text. Each 
method has a unique purpose, but they all return strings. You should perform all math operations as 
unformatted number objects because the values have the most precision. Only after you are ready to 
display the results should you use one of these methods to convert the number to a string for display 
as body text or assignment to a text field. 

The toExponential ( ) method forces a number to display in exponential notation, even if the 
number is in the range in which JavaScript normally uses standard notation. The parameter is 
an integer specifying how many digits to the right of the decimal should be returned. All digits 
that far to the right of the decimal are returned, even if they are zero. For example, if a variable 
contains the numeric value 345, applying toExponential (3) to that value yields 3.450e+2, 
which is JavaScript's exponential notation for 3.45 oo 10 2 . 

Use the toFi xed ( ) method when you want to format a number with a specific number of 
digits to the right of the decimal. This is the method you use, for instance, to display the results 
of a financial calculation in units and hundredths of units (for example, dollars and cents). 
The parameter to the method is an integer indicating the number of digits to be displayed 
to the right of the decimal. If the number being formatted has more numbers to the right of the 
decimal than the number of digits specified by the parameter, the method rounds the rightmost 
visible digit — but only with respect to the unrounded value of the next digit. For example, the value 
123.455 fixed to two digits to the right of the decimal is rounded up to 123.46. But if the starting 
value is 123. 4549, the method ignores the 9 and sees that the 4 to the right of the 5 should be 
rounded down; therefore, the result is 123.45. Do not consider the toFixed( ) method to be an 
accurate rounder of numbers; however, it does a satisfactory job in most cases. 

The final method is t o P r e c i s i o n ( ) , which enables you to define how many total digits of a num- 
ber (including digits to the left and right of the decimal) to display. In other words, you define the 
precision of a number. The following list demonstrates the results of several parameter values signify- 
ing a variety of precisions: 

va r num = 123.45 

num . toPreci s i on ( 1 ) // result = le+2 
num . toPreci s i on ( 2 ) // result = 1.2e+2 



282 



Chapter 16: The Math, Number, and Boolean Objects 



numberObject.toStringQ 

num . toPreci si on ( 3 ) // result = 123 
num . toPreci si on ( 4 ) // result = 123.5 
num . toPreci si on ( 5 ) // result = 123.45 
num . toPreci si on ( 6 ) // result = 123.450 

Notice that the same kind of rounding can occur with toPreci s i o n ( ) as it does for t o F i x e d ( ) . 



Example 

You can use The Evaluator (see Chapter 4) to experiment with all three of these methods, with a vari- 
ety of parameter values. Before invoking any method, be sure to assign a numeric value to one of the 
built-in global variables in The Evaluator (a through z). 

a = 10/3 

a .toFixed(4) 

"$" + a.toFixed(2) 

None of these methods works with number literals (for example, 123.toExponential (2) does not 
work). 

Related Items: Math object 

number. to Local eStri ng( ) 

Returns: String 

Compatibility: WmIE5.5+, MacIE5+, NN6+, Moz+, Safari+, Opera-F, Chrome+ 

The number. toLocaleString( ) method returns a string value version of the current number 
in a format that may vary according to a browser's locale settings. According to the ECMA Edition 
5 standard, browsers have some leeway in determining exactly how the toLocaleStringO 
method should return a string value that conforms with the language standard of the client system or 
browser. 

Related Items: number. toFixed( ), number. toString( ) methods 

number. toStri ng( [racffx] ) 

Returns: String 

Compatibility: WinIE4-F, MacIE44-, NN44-, Moz4-, Safari4-, Opera4-, Chrome4- 

The number. toString( ) method returns a string value version of the current number. The 
default radix parameter (10) converts the value to base-10 notation if the original number isn't 
already of that type. Or, you can specify other number bases (for example, 2 for binary, 1 6 for 
hexadecimal) to convert the original number to the other base — as a string, not a number — 
for further calculation. 



Example 

Use The Evaluator (Chapter 4) to experiment with the toStri ng( ) method. Assign the number 12 
to the variable a and see how the number is converted to strings in a variety of number bases: 



283 



Part III: JavaScript Core Language Reference 



booleanObject 

a = 12 

a.toStn'ngO // base 10 

a.toString(2) 

a.toString(16) 

Related Items: toLocal eStri ng ( ) method 

number .val ueOf ( ) 

(See stri ng . val ueOf ( ) in Chapter 15) 



Boolean Object 





Properties 


Methods 


constructor 


toStri ng( ) 


prototype 


val ueOf ( ) 


Syntax 

Creating a Bool ean object: 




var val = new BooleanO 


3ool eanVa 1 ue) ; 



Accessing Bool ean object properties: 



Bool eanObject . property \ method 
Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari+, Opera+, Chrome+ 

About this object 

You work with Boolean values a lot in JavaScript — especially as the result of conditional tests. Just as 
string values benefit from association with string objects, and their properties and methods, so, too, do 
Boolean values receive aid from the Bool ean object. For example, when you display a Boolean value 
in a text box, the "true" or "false" string is provided by the Boolean object's toStringO 
method, so you don't have to invoke it directly. 

The only time you need to even think about a Bool ean object is if you wish to attach some prop- 
erty or method to Boolean objects that you create with the new Bool ean ( ) constructor. Param- 
eter values for the constructor include the string versions of the values, numbers (0 for f al se; any 
other integer for true), and expressions that evaluate to a Boolean value. Any such new Bool ean 
object is imbued with the new properties or methods you add to the prototype property of the 
core Bool ean object. 

For details about the properties and methods of the Boolean object, see the corresponding listings 
for the Stri ng object in Chapter 15. 



284 



The Date Object 




Perhaps the most untapped power of JavaScript is its date and time han- 
dling. Scrip ters passed over the Date object with good cause in the early 
days of JavaScript, because in earlier versions of scnptable browsers, sig- 
nificant bugs and platform-specific anomalies made date and time programming 
hazardous without significant testing. Even with the improved bug situation, 
working with dates requires a working knowledge of the world's time zones and 
their relationships with the standard reference point, known as Greenwich Mean 
Time (GMT) or Coordinated Universal Time (abbreviated UTC). 

Now that date- and time-handling has stabilized in modern browsers, I hope 
more scripters look into incorporating these kinds of calculations into their 
pages. In Chapter 57, "Application: Intelligent 'Updated' Flags," on the CD-ROM, 
for example, I show you an application that lets your web site highlight the 
areas that have been updated since each visitor's last surf ride through your 
pages — an application that relies heavily on date arithmetic and time-zone 
conversion. 

Before getting to the JavaScript part of date discussions, however, the chapter 
summarizes key facts about time zones and their impact on scripting date and 
time on a browser. If you're not sure what GMT and UTC mean, the following 
section is for you. 



IN THIS CHAPTER 



Working with date and time 
values in JavaScript 

Performing date calculations 

Validating date entry form 
fields 



Time Zones and GMT 



By international agreement, the world is divided into distinct time zones that 
allow the inhabitants of each zone to say with confidence that when the Sun 
appears directly overhead, it is roughly noon, squarely in the middle of the day. 
The current time in the zone is what we set our clocks to — the local time. 

That's fine when your entire existence and scope of life go no further than the 
width of your own time zone. But with instant communication among all parts 
of the world, your scope reaches well beyond local time. Periodically you must 



285 



Part III: JavaScript Core Language Reference 



be aware of the local time in other zones. After all, if you live in New York, you don't want to wake 
up someone in Los Angeles before dawn with a phone call from your office. 

Note 

For the rest of this section, we speak of the Sun "moving" as if Earth were the center of the solar system. We 
do so for the convenience of our daily perception of the Sun arcing across what appears to us as a stationary 
sky. In point of fact, we believe Copernicus's theories, so please delete that email you were about to send us. ■ 

From the point of view of the time zone over which the Sun is positioned at any given instant, all 
time zones to the east have already had their noon, so it is later in the day for them — one hour later 
per time zone (except for those few time zones offset by fractions of an hour). That's why when U.S. 
television networks broadcast simultaneously to the eastern and central time zones, the announced 
schedule for a program is "10 eastern, 9 central." 

Many international businesses must coordinate time schedules of far-flung events. Doing so and 
taking into account the numerous time zone differences (not to mention seasonal national variations, 
such as daylight saving time) would be a nightmare. To help everyone out, a standard reference point 
was devised: the time zone running through the celestial observatory at Greenwich (pronounced 
GREN-itch), England. This time zone is called Greenwich Mean Time, or GMT for short. The "mean" 
part comes from the fact that on the exact opposite side of the globe (through the Pacific Ocean) is 
the international date line, another world standard that decrees where the first instance of the next 
calendar day appears on the planet. Thus, GMT is located at the middle, or mean, of the full circuit 
of the day. Not that many years ago, GMT was given another abbreviation that is not based on any 
one language of the planet. The abbreviation is UTC (pronounced as its letters: yu-tee-see), and the 
English version is Coordinated Universal Time. Whenever you see UTC, it is for all practical purposes 
the same as GMT. 

If your personal computer's system clock is set correctly, the machine ticks away in GMT time. But 
because you set your local time zone in the appropriate control panel, all file time stamps and clock 
displays are in your local time. The machine knows what the offset time is between your local time 
and GMT. For daylight savings time, you may have to check a preference setting so that the offset is 
adjusted accordingly; in Windows-based operating systems, the system knows when the changeover 
occurs and prompts you if changing the offset is okay. In any case, if you travel across time zones 
with a laptop, you should change the computer's time zone setting, not its clock. 

JavaScript's inner handling of date and time works a lot like the PC clock (on which your programs 
rely). Date values that you generate in a script are stored internally in GMT time; however, almost 
all the displays and extracted values are in the local time of the visitor (not the web site server). And 
remember that the date values are created on the visitor's machine by virtue of your script's generating 
that value — you don't send "living" date objects to the client from the server. This concept is perhaps 
the most difficult to grasp as you work with JavaScript date and time. 

Whenever you program time and date in JavaScript for a public web page, you must take the world- 
view. This view requires knowing that the visitor's computer settings determine the accuracy of the 
conversion between GMT and local time. You'll also have to do some testing by changing your PC's 
clock to times in other parts of the world and making believe you are temporarily in those remote 
locations, which isn't always easy to do. It reminds me (Danny) of the time I was visiting Sydney, Aus- 
tralia. I was turning in for the night and switched on the television in the hotel. This hotel received a 
live satellite relay of a long-running U.S. television program, Today. The program broadcast from New 
York was for the morning of the same day I was just finishing in Sydney. Yes, this time zone stuff can 
make your head hurt. 



286 



Chapter 17: The Date Object 



The Date Object 

Like a handful of other objects in JavaScript and the document object models, there is a distinction 
between the single, static Date object that exists in every window (or frame) and a date object that 
contains a specific date and time. The static Date object (uppercase D) is used in only a few cases: 
Primarily to create a new instance of a date and to invoke a couple of methods that the Date object 
offers for the sake of some generic conversions. 

Most of your date and time work, however, is with instances of the Date object. These instances are 
referred to genetically as date objects (lowercase d). Each date object is a snapshot of an exact millisec- 
ond in time, whether it be for the instant at which you generate the object or for a specific time in the 
past or future you need for calculations. If you need to have a live clock ticking away, your scripts 
will repeatedly create new date objects to grab up-to-the-millisecond snapshots of your computer's 
clock. To show the time on the page, extract the hours, minutes, and seconds from the snapshot date 
object, and then display the values as you like (for example, a digital readout, a graphical bar chart, 
and so on). By and large, it is the methods of a date object instance that your scripts invoke to read 
or modify individual components of a date object (for example, the month or hour). 

Despite its name, every date object contains information about date and time. Therefore, even if you're 
concerned only about the date part of an object's data, time data is standing by as well. As you learn 
in a bit, the time element can catch you off-guard for some operations. 

Creating a date object 

The statement that asks JavaScript to make an object for your script uses the special object construc- 
tion keyword new. The basic syntax for generating a new date object is as follows: 

var dateObj ectName = new Date( [parameters] ) ; 

The date object evaluates to an object data type rather than to some string or numeric value. 

With the date object's reference safely tucked away in the variable name, you access all date-oriented 
methods in the dot-syntax fashion with which you're already familiar: 

var result = dateObjectName .methodi) ; 

With variables, such as res ill t, your scripts perform calculations or displays of the date object's data 
(some methods extract pieces of the date and time data from the object). If you then want to put some 
new value into the date object (such as adding a year to the date object), you assign the new value to 
the object by way of the method that lets you set the value: 

da teObjectName . methodi new]/ a l ue) ; 

This example doesn't look like the typical JavaScript assignment statement, which has an equals sign 
operator. But this statement is the way in which methods that set date object data work. 

You cannot get very far into scripting dates without digging into time zone arithmetic. Although 
JavaScript may render the string equivalent of a date object in your local time zone, the internal 
storage is strictly GMT. 

Even though you haven't yet seen details of a date object's methods, here is how you use two of them 
to add one year to today's date: 

var oneDate = new DateO; // creates object with current GMT date 

var theYear = oneDate. getYeart ) ; // stores the current tour-digit year 



287 



Part III: JavaScript Core Language Reference 



theYear = theYear + 1 ; 
oneDate.setYear(theYear) ; 



// theYear now is next year 

// the new year value now in the object 



At the end of this sequence, the one Date object automatically adjusts all the other date components 
for the next year's date. The day of the week, for example, will be different, and JavaScript takes care 
of that for you, should you need to extract that data. With next year's data in the one Date object, 
you may now want to extract that new date as a string value for display in a field on the page or sub- 
mit it quietly to a CGI program on the server. 

The issue of parameters for creating a new date object is a bit complex, mostly because of the flex- 
ibility that JavaScript offers the scripter. Recall that the job of the new Date ( ) statement is to cre- 
ate a place in memory for all data that a date needs to store. What is missing from that task is the 
data — what date and time to enter into that memory spot. That's where the parameters come in. 

If you leave the parameters empty, JavaScript takes that to mean you want today's date and the current 
time to be assigned to that new date object. JavaScript isn't any smarter, of course, than the setting of 
the internal clock of your page visitor's personal computer. If the clock isn't correct, JavaScript won't 
do any better of a job identifying the date and time. 



Remember that when you create a new date object, it contains the current time as well. The fact that the cur- 
rent date may include a time of 16:03:19 (in 24-hour time) may throw off things, such as days-between-dates 
calculations. Be careful. ■ 



To create a date object for a specific date or time, you have five ways to send values as a parameter to 
the new Date( ) constructor function: 

new Date( "Month 66, yyyy hh: mm: ss" ) 

new Date( "Month 66, yyyy") 

new Date iyy, mm , 66, hh, mm, ss ) 

new Date(yy, mm, 66) 

new Date(/7?7 1 1 i secon6s) 

The first four variations break down into two styles — a long string versus a comma-delimited list of 
data — each with optional time settings. If you omit time settings, they are set to 0 (midnight) in the 
date object for whatever date you entered. You cannot omit date values from the parameters — every 
date object must have a real date attached to it, whether you need it or not. 

In the long string versions, the month is spelled out in full in English. No abbreviations are allowed. 
The rest of the data is filled with numbers representing the date, year, hours, minutes, and seconds, 
even if the order is different from your local way of indicating dates. For single-digit values, you can 
use either a one- or two-digit version (such as 4:05:00). Colons separate hours, minutes, and seconds. 

The short versions contain a non-quoted list of integer values in the order indicated. JavaScript cannot 
know that a 30 means the day if you accidentally place it in the month slot. 

You use the last version only when you have the millisecond value of a date and time available. This 
generally occurs after some math arithmetic (described later in this chapter), leaving you with a date 
and time in millisecond format. To convert that numeric value to a date object, use the new Date( ) 
constructor. From the new date object created, you can retrieve more convenient values about the date 
and time. 



Note 



288 



Chapter 17: The Date Object 



Native object properties and methods 

Like the String and Array objects, the Date object features a small handful of properties 
and methods that all native JavaScript objects have in common. On the property side, the Date 
object has a prototype property, which enables you to apply new properties and methods 
to every date object created in the current page. You can see examples of how this works 
in discussions of the prototype property for String and Array objects (Chapters 15 and 
18, respectively). At the same time, every instance of a date object in modern browsers has a 
constructor property that references the constructor function that generated the object. 

A date object has numerous methods that convert date object types to strings, most of which are more 
specific than the generic toStri ng ( ) one. The val ueOf ( ) method returns the millisecond integer 
that is stored for a particular date. 

Date methods 

The bulk of a date object's methods are for reading parts of the date and time information and for 
changing the date and time stored in the object. These two categories of methods are easily identifiable 
because they all begin with the word "get" or "set." 

Table 17-1 lists all of the methods of both the static Date object and, by inheritance, date 
object instances. The list is impressive — some would say frightening — but there are patterns 
you should readily observe. Most methods deal with a single component of a date and time 
value: year, month, date, and so forth. Each block of "get" and "set" methods also has two sets of 
methods: one for the local date and time conversion of the date stored in the object; one for the 
actual UTC date stored in the object. After you see the patterns, the list should be more manageable. 
Unless otherwise noted, a method has been part of the Date object since the first generation of 
scriptable browsers, and is therefore also supported in newer browsers. 

Deciding between using the UTC or local versions of the methods depends on several factors. If the 
browsers you must support go back to the beginning, you will be stuck with the local versions in 
any case. But even for newer browsers, activities, such as calculating the number of days between 
dates or creating a countdown timer for a quiz, won't care which set you use, but you must use the 
same set for all calculations. If you start mixing local and UTC versions of date methods, you'll be 
destined to get wrong answers. The UTC versions come in most handy when your date calculations 
must take into account the time zone of the client machine compared to some absolute in another 
time zone — calculating the time remaining to the chiming of Big Ben signifying the start of the New 
Year in London. 

JavaScript maintains its date information in the form of a count of milliseconds (thousandths of a sec- 
ond) starting from January 1, 1970, in the GMT (UTC) time zone. Dates before that starting point are 
stored as negative values (but see the section on bugs and gremlins later in this chapter). Regardless 
of the country you are in or the date and time formats specified for your computer, the millisecond 
is the JavaScript universal measure of time. Any calculations that involve adding or subtracting times 
and dates should be performed in the millisecond values to ensure accuracy. Therefore, though you 
may never display the milliseconds value in a field or dialog box, your scripts will probably work with 
them from time to time in variables. To derive the millisecond equivalent for any date and time stored 
in a date object, use the dateObj .getTime( ) method, as in 

var startDate = new Date(); 

var started = sta rtDate . getTi me ( ) ; 



289 



Part III: JavaScript Core Language Reference 



TABLE 17-1 



Date Object Methods 


Method 




Value Range 


Description 


dateOb j 


. getFul 1 Yea r ( ) 


1970-.. . 


Specified year (NN4+, Moz1+, IE3+) 


dateObj 


. getYear( ) 


70-... 


(See text of chapter) 


dateOb i 

■j u I, \~ \j kj ,j 


. getMontht ) 


0-11 


Month within the year (January = 0) 


dateObj 


.getDate( ) 


1-31 


Date within the month 


dateObj 


.getDay( ) 


0-6 


Day of week (Sunday = 0) 


dateObj 


. getHours ( ) 


0-23 


Hour of the day in 24-hour time 


dateObj 


. getMi nutes ( ) 


0-59 


Minute of the specified hour 


aazeuDj 


. getSeconds ( ) 


n k q 


Second within the specified minute 


dateObj 


. getTi me ( ) 


0-... 


Milliseconds since 1/1/70 00:00:00 GMT 


dateObj 


. getMi 1 1 i seconds ( ) 


0-999 


Milliseconds since the previous full 
second (NN4+, Moz1+, IE3+) 


dateObj 


.getUTCFullYearO 


1970-.. . 


Specified UTC year (NN4+, Moz1+, 
IE3+) 


dateObj 


,getUTCMonth( ) 


0-11 


UTC month within the year (January = 0) 
(NN4+, Moz1+, IE3+) 


dateObj 


.getUTCDate( ) 


1-31 


UTC date within the month (NN4+, 
Moz1+, IE3+) 


dateObj 


,getUTCDay( ) 


0-6 


UTC day of week (Sunday = 0) (NN4+, 

\/t^.-7l I ICQ I 
/VlOZ I +, ItJ+J 


rl a +■ a H h -i 
G d I GU D J 




U — L. o 


UTC hour of the clay in 24-hour time 
(NN4+, Moz1+, IE3+) 


dateObj 


,getUTCMinutes( ) 


0-59 


UTC minute of the specified hour 
(NN4+, Moz1+, IE3+) 


dateObj 


. getUTCSeconds ( ) 


0-59 


UTC second within the specified minute 
(NN4+, Moz1+, IE3+) 


dateObj 


.getUTCMill i seconds ( ) 


0-999 


UTC milliseconds since the previous full 
second (NN4+, Moz1+, IE3+) 


dateObj 


. setYea r ( va 1 ) 


1970-.. . 


Be safe: always specify a four-digit year 


dateObj 


. set Ful 1 Yea r ( va 1 ) 


1970-.. . 


Specified year (NN4+, Moz1+, IE3+) 


dateObj 


. setMonth ( va 1 ) 


0-11 


Month within the year (January = 0) 


dateObj 


. setDate( va 1 ) 


1-31 


Date within the month 



290 



Chapter 17: The Date Object 



Method 




Value Range 


Description 


dateObj 


. setDay ( va 1 ) 


0- 


-6 


Day ot week (Sunday = 0) 


dateObj 


. setHours ( va 1 ) 


0- 


-23 


Hour of the day in 24-hour time 


dateObj 


. setMi nutes (val) 


0- 


-59 


Minute of the specified hour 


dateObj 


, setSeconds (val) 


0- 


-59 


Second within the specified minute 


dateObj 


, setMi 1 1 i seconds (.val) 


0 


-999 


Milliseconds since the previous full 
second (NN4+, Moz1+, IE3+) 


dateObj 


. setTi me(val) 


0- 




Milliseconds since 1/1/70 00:00:00 GMT 


dateObj 


.setUTCFullYearUa/) 


1970-.. . 


Specified UTC year (NN4+, Moz1+, 
IE3+) 


dateObj 


,setUTCMonth( val) 


n 

u - 


1 1 


UTC month within the year (January = 0) 
(NN4+, Moz1+, IE3+) 


dateObj 


,setUTCDate( val) 


1- 


-31 


UTC date within the month (NN4+, 
Moz1+, IE3+) 


dateObj 


. setUTCDay( val) 


0- 


-6 


UTC day of week (Sunday = 0) (NN4+, 
Moz1+, IE3+) 


dateObj 


. setUTCHours (val) 


0- 


-23 


UTC hour of the day in 24-hour time 
(NN4+, Moz1+, IE3+) 


dateObj 


. setUTCMi nutes (val) 


0- 


-59 


UTC minute of the specified hour 
(NN4+, Moz1+, IE3+) 


dateObj 


. setUTCSeconds ( va 1 ) 


0- 


-59 


UTC second within the specified minute 
(NN4+, Moz1+, IE3+) 


dateObj 


.setUTCMilliseconds(i/a/) 


0 


-999 


UTC milliseconds since the previous full 
second (NN4+, Moz1+, IE3+) 


dateObj 


. getTimezoneOffset() 


0- 




Minutes offset from GMT/UTC 


dateObj 


. toDateSt ri ng ( ) 






Date-only string in a format determined 
by browser (WinlE5.5+) 


dateObj 


.toGMTString( ) 






Date/time string in universal format 


dateObj 


. toLocaleDateString() 






Date-only string in your system's 

nr a I i 7(arl fnrmat ( SJ \J A— I— N/1 /~> 7 1 -U 
IL*L-cillZ.fc;U IUIIIIcH IJNIN UT/ JVIUZ. I \^ t 

WinlE5.5+) 


dateObj 


. toLocal eStri ng( ) 






Date/time string in your system's 
localized format 


dateObj 


.toLocaleTimeString() 






Time-only string in your system's 
localized format (NN6+, Moz1+, 
WinlE5.5+) 



continued 



291 



Part III: JavaScript Core Language Reference 





Method 


Value Range 


Description 


dateObj . toStri ng( ) 




Date/time string in a format determined by 
browser 


dateObj.toTimeString() 




Time-only string in a format determined by 
browser (WinlE5.5+) 


dateObj . toUTCStri ng ( ) 




Date/time string in universal format 
(NN4+, Moz1+, IE3+) 


Date. parse(" da teStr i ng" ) 




Converts string date to milliseconds integer 


Date . UTC ( da te values) 




Converts GMT string date to milliseconds 
integer 



Although the method has the word "time" in its name, the fact that the value is the total number of 
milliseconds from January 1, 1970, means the value also conveys a date. 

Other date object get methods read a specific component of the date or time. You have to exercise 
some care here, because some values begin counting with 0 when you may not expect it. For example, 
January is month 0 in JavaScript's scheme; December is month 11. Hours, minutes, and seconds all 
begin with 0, which, in the end, is logical. Calendar dates, however, use the actual number that would 
show up on the wall calendar: the first day of the month is date value 1 . For the twentieth-century 
years, the year value is whatever the actual year number is, minus 1900. For 1996, that means the 
year value is 96. But for years before 1900 and after 1999, JavaScript uses a different formula, show- 
ing the full year value. This means you have to check whether a year value is less than 100 and add 
1900 to it before displaying that year. 

va r today = new Date ( ) ; 

var thisYear = today . getYea r () ; 

if (thisYear < 100) 

{ 

thisYear += 1900; 

) 

This assumes, of course, you won't be working with years before A.D. 100. If you can 
assume that your audience is using a modern browser, which is quite likely, use only the 
getFullYearO method. This method returns the complete set of year digits from all ranges. 

To adjust any one of the elements of a date value, use the corresponding set method in an assignment 
statement. If the new value forces the adjustment of other elements, JavaScript takes care of that. For 
example, consider the following sequence and how some values are changed for us: 

myBirthday = new Date("July 4, 1776"); 
result = myBi rthday . getDay ( ) ; // result = 4, a Thursday 
myBi rthday . setYear( 1777 ) ; // bump up to next year 
result = myBi rthday . getDay () ; // result = 5, a Friday 

Because the same date in the following year is on a different day, JavaScript tracks that for you. 



292 



Chapter 17: The Date Object 



Accommodating time zones 

Understanding the dateObj .getTimezoneOffset( ) method involves both your operating sys- 
tem's time control panel setting and an internationally recognized (in computerdom, anyway) format 
for representing dates and times. If you have ignored the control panel stuff about setting your local 
time zone, the values you get for this property may be off for most dates and times. In the eastern part 
of North America, for instance, the eastern standard time zone is five hours earlier than Greenwich 
Mean Time. With the getTimezoneOffset( ) method producing a value of minutes' difference 
between GMT and the PC's time zone, the five hours difference of eastern standard time is rendered as 
a value of 300 minutes. On the Windows platform, the value automatically changes to reflect changes 
in daylight saving time in the user's area (if applicable). Offsets to the east of GMT (to the date line) 
are expressed as negative values. 



Dates as strings 

When you generate a date object, JavaScript automatically applies the t o S t r i n g ( ) method to the 
object if you attempt to display that date either in a page or alert box. The format of this string varies 
with browser and operating system platforms. For example, in IE8 for Windows XP, the string is in 
the following format: 

Sun Dec 5 16:47:20 PST 2010 
But in Firefox 3 for Windows XP, the string is 

Sun Dec 05 2010 16:47:20 GMT-0800 (Pacific Standard Time) 

Other browsers return their own variations on the string. The point is not to rely on a specific format 
and character location of this string for the components of dates. Use the date object methods to read 
date object components. 

JavaScript does, however, provide two methods that return the date object in more constant string 
formats. One, dateObj .toGMTString( ), converts the date and time to the GMT equivalent on the 
way to the variable that you use to store the extracted data. Here is what such data looks like: 

Mon, 06 Dec 2010 00:47:20 GMT 

If you're not familiar with the workings of GMT and how such conversions can present unexpected 
dates, exercise great care in testing your application. A quarter to five on a Sunday afternoon on the 
North American west coast is well after midnight Monday morning at the Royal Observatory in Green- 
wich, London. 

If time zone conversions make your head hurt, you can use the second string method, 
dateObj .tol_ocaleString( ). In Firefox for North American Windows users, the returned 
value can look like this: 

Sunday, December 05, 2010 4:47:20 PM 

Ever since IE5.5 and NN6/Mozl, you can also have JavaScript convert a date object to just 
the date or time portions in a nicely formatted version. The best pair of methods for this are 
toLocaleDateString( ) and to Local eTi me St r i ng ( ) , because these methods return values 
that make the most sense to the user, based on the localization settings of the user's operating system 
and browser. 



293 



Part III: JavaScript Core Language Reference 



Friendly date formats for older browsers 

If you don't have the luxury of writing script code only for modern browsers, you can create your own 
formatting function to do the job for a wide range of browsers. Listing 17-1 demonstrates one way of 
creating this kind of string from a date object (in a form that will work back to version 4 browsers). 

Note 

The function to assign event handlers throughout the code in this chapter and much of the book is 
addEvent( ), a cross-browser event handler explained in detail in Chapter 32, "Event Objects." 

The add Event ( ) function is part of the script file jsb-global . js located on the accompanying CD-ROM 
in the Content/ folder, where it is accessible to all chapters' scripts. ■ 



LISTING 17-1 



Creating a Friendly Date String 

HTML: jsb-17-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Date String Maker</ti tl e> 

<script type=" text /javascript" src=". ./jsb-global . js "></scn'pt> 
<script type="text/ j avascri pt" src=" j sb- 17 -01 . j s "></scri pt> 

</head> 

<body> 

<hl>Date String Maker</hl> 
<p i d="output">Today ' s date</p> 
</body> 
</html > 

JavaScript: jsb-17-01.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

monthNames = ["January", "February", "March", "April", "May", "June", "July", 
"August", "September", "October", "November", "December"]; 

dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
"Saturday"] ; 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld ) 

{ 

// point to the paragraph to contain the date 
oOutput = document . getEl ementByld (' output ') ; 

// if it exists, replace its contents with the date 



294 



Chapter 17: The Date Object 



if (oOutput) 
{ 

// remove all child nodes from the paragraph 

while ( oOutput . f i rstChi I d ) 

{ 

oOutput. removeChild(oOutput.firstChild); 

) 



// create a text node with the date 

var sDate = customDateStri ng ( new DateO); 

var oNewText = document . createTextNode ( sDate ) ; 



// insert that content into the paragraph 
oOutput. appendChild(oNewText) ; 



// generate a formatted date 
function customDateStri ng( oDate) 
{ 

var theDay = dayNames [oDate . getDay ( ) ] ; 

var theMonth = monthNames[oDate.getMonth( )] ; 

var theYear = oDate . getFul I Year( ) ; 

return theDay + ", " + theMonth + " " + oDate . getDate( ) + ", " + theYear; 

) 



Assuming the user has the PC's clock set correctly (a big assumption), the date appearing 
just below the opening headline is the current date — making it appear as though the doc- 
ument had been updated today. The downside to this approach (as opposed to the newer 
toLocaleDateString( ) method) is that international users are forced to view dates in the format 
you design, which may be different from their local custom. 



More conversions 

The last two methods shown in Listing 17-1 are methods of the static Date object. These utility meth- 
ods convert dates from string or numeric forms into millisecond values of those dates. The primary 
beneficiary of these actions is the dateOb j . setTi me ( ) method, which requires a millisecond mea- 
sure of a date as a parameter. You use this method to throw an entirely different date into an existing 
date object. 

Date.parse( ) accepts as a parameter date strings similar to the ones you've seen in this section, 
including the internationally approved version. Date.UTC(),on the other hand, requires the 
comma-delimited list of values (in proper order: yy , mm , dd , h h , mm , s s) in the GMT zone. The 
Date . LIT C( ) method gives you a backward-compatible way to hard-code a GMT time (you can do 
the same in version 4 browsers via the UTC methods). The following is an example that creates a new 
date object for 6 p.m. on October 1, 2011, GMT in WinIE8: 

var newObj = new Datet Date . UTC( 2011 , 9, 1, 18, 0, 0)); 

result = newObj .toStringt ) ; // result = "Sat Oct 1 11:00:00 PDT2011" 



295 



Part III: JavaScript Core Language Reference 



The second statement returns a value in a local time zone, because all non-UTC methods automatically 
convert the GMT time stored in the object to the client's local time. 

Date and time arithmetic 

You may need to perform some math with dates for any number of reasons. Perhaps you need to 
calculate a date at some fixed number of days or weeks in the future or figure out the number of 
days between two dates. When calculations of these types are required, remember the lingua jranca 
of JavaScript date values: milliseconds. 

What you may need to do in your date-intensive scripts is establish some variable values representing 
the number of milliseconds for minutes, hours, days, or weeks, and then use those variables in your 
calculations. Here is an example that establishes some practical variable values, building on each other: 

var oneMinute = 60 * 1000; 

var oneHour = oneMinute * 60; 

var oneDay = oneHour * 24; 

var oneWeek = oneDay * 7; 

With these values established in a script, I can use one to calculate the date one week from today: 

var targetDate = new Date(); 

var datelnMs = ta rgetDate . getTi me ( ) ; 

datelnMs += oneWeek; 

targetDate. setTime(datelnMs) ; 

Another example uses components of a date object to assist in deciding what kind of greeting mes- 
sage to place in a document, based on the local time of the user's PC clock. Listing 17-2 adds to the 
scripting from Listing 17-1, bringing some quasi-intelligence to the proceedings. 



LISTING 17-2 



A Dynamic Welcome Message 

HTML: jsb-17-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Date String Maker</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 

<script type="text/ j avascri pt" src=" j sb- 17 -02 . j s "></scri pt> 
</head> 
<body> 

<hl>Welcome!</hl> 

<p i d="date">Today ' s date</p> 

<p>We hope you are enjoying the <span id="day-part">day</span>.</p> 
</body> 
</html > 



296 



Chapter 17: The Date Object 



JavaScript: jsb-17-02.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 



monthNames = ["January", "February", "March", "April", "May", "June", "July", 
"August", "September", "October", "November", "December"]; 

dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
"Saturday"] ; 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to the target paragraphs 

var oDateDisplay = document . getEl ementBy Id (' date ') ; 

var oGreeting = document . getEl ementBy Id( ' greeti ng ') ; 



// if they exist, plug in new content 

if (oDateDisplay && oGreeting) 

{ 

// plug in date 

var oNow = new Date( ) ; 

var sDate = customDateStri ng( oNow) ; 

rep I aceTextContent ( oDateDisplay, sDate); 



// plug day-part into greeting 

var sDayPart = dayPart(oNow) ; 

rep I aceTextContent ( oGreeting, sDayPart); 

I 

I 

) 



// generate a formatted date 
function customDateStri ng( oDate ) 
{ 

var theDay = dayNames[oDate.getDay( )] ; 

var theMonth = monthNames [oDate . getMonth ()] ; 

var theYear = oDate . getFul I Year( ) ; 

return theDay + ", " + theMonth + " " + oDate . getDate ( ) + ", " + theYear; 

) 



// get the part of the day 
function dayPart(oDate) 
{ 

var theHour = oDate . getHours ( ) ; 
if (theHour < 6 ) 

return "wee hours"; 
if (theHour < 12) 

return "morning"; 
if (theHour < 18) 

continued 



297 



Part III: JavaScript Core Language Reference 



LISTING 17-2 



(continued) 



return "afternoon' 
return "evening"; 



// replaces the text contents of a page element 
function repl acef extContent ( oEl ement , sContent) 



I 



// if the object exists 

if (oElement) 

{ 

// remove all child nodes 
while ( oEl ement . fi rstChi 1 d ) 
{ 

oEl ement .removeChild(oEl ement .firstChild); 



// create a text node with the new content 

var oNewText = document . createTextNode( sContent ) 



// insert that content 

oEl ement . appendChi 1 d ( oNewText ) ; 



The script divides the day into four parts and presents a different greeting for each part of the day. 
The greeting that plays is based, simply enough, on the hour element of a date object representing the 
time the page is loaded into the browser. Because this greeting is embedded in the page, the greeting 
does not change no matter how long the user displays the page, but it will update each time the page 
is reloaded. 



Counting the days . . . 

You may find one or two more date arithmetic applications useful. One displays the number of shop- 
ping days left until Christmas (in the user's time zone); the other is a countdown timer to the start of 
the year 2100. 

Listing 17-3 demonstrates how to calculate the number of days between the current day and some 
fixed date in the future. The assumption in this application is that all calculations take place in the 
user's time zone. The example shows the display of the number of shopping days before the next 
Christmas day (December 25). The basic operation entails converting the current date and the next 
December 25 to milliseconds, calculating the number of days represented by the difference in millisec- 
onds. If you let the millisecond values represent the dates, JavaScript automatically takes care of leap 
years. 

The only somewhat tricky part is setting the year of the next Christmas day correctly. You can't just 
slap the fixed date with the current year, because if the program is run on December 26, the year of 
the next Christmas must be incremented by one. That's why the constructor for the Christmas date 



298 



Chapter 17: The Date Object 



object doesn't supply a fixed date as its parameters, but rather, sets individual components of the 
object. 

Also, note that while setDate( ) accepts a counting number 1-31, setMonth( ) accepts a whole 
number 0-11, making December month 11 for that method call. 



LISTING 17-3 



How Many Days Until Christmas 



HTML: jsb-17-03.html 



<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Chri stmas Countdown</title> 

<script type=" text/javascript" src="../jsb-global .js"X/script> 
<script type=" text/javascript" src="jsb-17-03.js"X/script> 

</head> 

<body> 

<hl>Chri stmas Countdown</hl> 

<p>You have <em id="days-l eft">too few</em> shopping 
<span id="day-word">days</span> until Chri stmas . </p> 
</body> 
</html > 



JavaScript: jsb-1703.js 



// initialize when the page has loaded 
addEvent(window, 'load', initialize); 



function i n i t i a 1 i z e ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . get El ementBy Id ) 

{ 

// point to the target paragraphs 

var oOutput = document . get El ementById( ' days-1 eft ') ; 

var oDayWord = document . get El ementBy Id (' day-word ') ; 



// if they exist, plug in new content 

if (oOutput && oDayWord) 

{ 

// plug in days left 

var sDaysLeft = getDaysUnti 1 Xmas ( ) ; 

replaceTextContent(oOutput, sDaysLeft) ; 

continued 



299 



Part III: JavaScript Core Language Reference 




(continued) 



II pluralize day if not one 

var sDayWord = (sDaysLeft == 1) ? 'day' 

replaceTextContent(oDayword, sDayWord) ; 



'days ' ; 



// calculate the number of days till next Christmas 
function getDaysUnti 1 Xmas ( ) 

{ 

var oneMinute = 60 * 1000; 
var oneHour = oneMinute * 60; 
var oneDay = oneHour * 24; 

var today = new Date ( ) ; 
var nextXmas = new Date(); 
nextXmas.setMonth(ll) ; 
nextXmas. setDate(25) ; 

if (today .getMonth( ) == 11 && today . getDate ( ) > 25) 



nextXmas . set Ful 1 Yea r ( nextXmas . get Ful 1 Yea r ( ) + 1); 

1 

var diff = nextXmas . getfime( ) - today . getfi me () ; 
diff = Math . fl oor( di ff /oneDay ) ; 
return diff; 



// replaces the text contents of a page element 
function repl acef extContent ( oEl ement , sContent) 

{ 

[see listing 17-2] 

1 



The second variation on calculating the amount of time before a certain event takes time zones into 
account. For this demonstration, the page is supposed to display a countdown timer to the precise 
moment when the flame for the 2008 Summer Games in Beijing is to be lit. That event takes place 
in a time zone that may be different from that of the page's viewer, so the countdown timer must 
calculate the time difference accordingly. 

Listing 17-4 shows a simplified version that simply displays the ticking timer in a text field. The out- 
put, of course, could be customized in any number of ways, depending on the amount of dynamic 
HTML you want to employ on a page. The time of the lighting for this demo is set at 11:00 GMT on 
August 8, 2008 (the date is certainly accurate, but the officials may set a different time closer to the 
actual event). 

Because this application is implemented as a live ticking clock, the code starts by setting some 
global variables that should be calculated only once so that the function that gets invoked 
repeatedly has a minimum of calculating to do (to be more efficient). The Date . LIT C( ) method 



300 



Chapter 17: The Date Object 



provides the target time and date in standard time. The getfimellntiK) function accepts a 
millisecond value (as provided by the targetDate variable) and calculates the difference between 
the target date and the actual internal millisecond value of the client's PC clock. 

The core of the getCountDown ( ) function peels off the number of whole days, hours, minutes, and 
seconds from the total number of milliseconds difference between now and the target date. Notice 
that each chunk is subtracted from the total so that the next-smaller chunk can be calculated from the 
leftover milliseconds. 

One extra touch on this page is a display of the local date and time of the actual event. 



LISTING 17-4 



Summer Games Countdown 

HTML: jsb-17-04.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 
<title>Time Since the First Moon Landi ng</ti tl e> 
<script type=" text/javascript" src="../jsb-global .js"X/script> 
<script type=" text/javascript" src="jsb-17-04.js"X/script> 

</head> 

<body> 

<hl>Time Since the First Moon Landing</hl> 

<p> I t is now <span id="now">the present</span> in your timezone . </p> 
<p><span i d="time-si nce">Many days</span> have passed since the first 
moon landing on <span i d="past-day ">a day long ago</span> . </p> 
</body> 
</html > 

JavaScript: jsb-1704.js 

// initialize when the page has loaded 
add Event (wi ndow , 'load', initialize); 

function i n i t i a 1 i z e ( ) 

{ 

// do this only if the browser can handle DOM methods 

if ( document . get El ementBy Id ) 

1 

// point to the target elements 

oOutputNow = document . get El ementBy Id (' now ') ; 

oOutputTi meSi nee = document . getEl ementBy Id( ' time-si nee ') ; 

var oOutputPastDay = document . get El ementBy Id (' past-day ') ; 

// if they exist, plug in new content 

continued 



301 



Part III: JavaScript Core Language Reference 



LISTING 17-4 



(continued) 



if (oOutputNow && oOutputTimeSince && oOutputPastDay ) 
{ 

// globals -- calculate only once 

// set tanget date to 20:17 UTC on July 20, 1969 

targetDate = Date . UTC( 1969 , 6, 20, 20, 17, 0, 0); 

oneSecond = 1000; 

oneMinute = oneSecond * 60; 

oneHour = oneMinute * 60; 

oneDay = oneHour * 24; 

// plug in the past date 

var sPastDay = (new Date ( ta rgetDate ) ) . toLocal eSt ri ng ( 
replaceTextContent( oOutputPastDay, sPastDay) ; 

// plug in current time & time since 
updateCounter( ) ; 



! 

// timer loop to display changing values 
function updateCounter ( ) 

{ 

// plug in current time 

var sNow = (new Date ( ) ) . toLocal eSt ri ng ( ) ; 

replacefextContent(oOutputNow, sNow); 

// plug in days since 

var sfimeSince = f ormatTi meSi nee ( ) ; 

replacefextContent(oOutputfimeSince, sfimeSince) 



setfimeout("updateCounter()", 1000) 



! 



// format elapsed time 
function f ormatf i meSi nee ( ) 

{ 

var ms = getfi meDi ff ( ta rgetDate ] 
var days, hrs, mins, sees; 

days = Ma th . fl oor ( ms /oneDay ) ; 
output = days + " Day " ; 

if (days != 1) output += 's'; 

ms -= oneDay * days ; 
hrs = Math . f 1 oor(ms/oneHour) ; 
output += ", " + hrs + " Hour"; 
if (hrs != 1) output += ' s ' ; 



302 



Chapter 17: The Date Object 



ms -= oneHour * hrs; 
mins = Math . f I oor ( ms /oneMi nute ) ; 
output += ", " + mins + " Minute"; 
if (mins != 1) output += 's'; 

ms -= oneMinute * mins; 
sees = Math . fl oor ( ms /oneSecond ) ; 
output += ", and " + sees + " Second"; 
if (sees != 1) output += 's'; 

return output; 

} 

// get the difference between two dateti 
function getfimeDiff(targetMS) 

{ 

va r today = new Date ( ) ; 
var diff = Math . abs ( today . val ueOf ( ) - 
return Math . fl oor ( di ff) ; 

} 

// replaces the text contents of a page element 
function repl acef extContent ( oEl ement , sContent) 

{ 

[see listing 17-2] 

1 



mes in mi 1 1 i seconds 



targetMS) ; 



Early browser date bugs and gremlins 

Each new browser generation improves the stability and reliability of scripted date objects. For 
example, Netscape Navigator 2 had so many bugs and crash problems that it made scripting complex 
world-time applications for this browser impossible. NN3 improved matters a bit, but some glaring 
problems still existed. And lest you think I'm picking on Netscape, rest assured that early versions of 
Internet Explorer also had plenty of date and time problems. IE3 couldn't handle dates before January 
1, 1970 (GMT), and also completely miscalculated the time zone offset, following the erroneous 
pattern of NN2. Bottom line — you're asking for trouble if you must work extensively with dates and 
times while supporting legacy browsers. 

You should be aware of one more discrepancy between Mac and Windows versions of Navigator 
through Version 4. In Windows, if you generate a date object for a date in another part of the year, 
the browser sets the time zone offset for that object according to the time zone setting for that 
time of year. On the Mac, the current setting of the control panel governs whether the normal or 
daylight savings time offset is applied to the date, regardless of the actual date within the year. This 
discrepancy affects Navigator 3 and 4 and can throw off calculations from other parts of the year by 
one hour. 

It may sound as though the road to Date object scripting is filled with land mines. Although date 
and time scripting is far from hassle free, you can put it to good use with careful planning and a lot 
of testing. Better still, if you make the plausible assumption that the majority of users have a modern 
browser (WinIE6+, NN64-, Mozl4-, FF1+, Caml+, Safaril+, etc.), then things should go very 
smoothly. 



303 



Part III: JavaScript Core Language Reference 



Validating Date Entries in Forms 

Given the bug horror stories in the previous section, you may wonder how you can ever perform data 
entry validation for dates in forms. The problem is not so much in the calculations as it is in the wide 
variety of acceptable date formats around the world. No matter how well you instruct users to enter 
dates in a particular format, many will follow their own habits and conventions. Moreover, how can 
you know whether an entry of 03/04/2010 is the North American March 4, 2010 or the European 
April 3, 2010? The answer: you can't. 

My recommendation is to divide a date field into three components: month, day, and year. 
Let the user enter values into each field and validate each field individually for its valid range. 
Listing 17-5 shows an example of how this is done. The page includes a form that is to be validated 
before it is submitted. Each component field does its own range checking on-the-fly as the user enters 
values. But because this kind of validation can be defeated, the page includes one further check 
triggered by the form's onsubmi t event handler. If any field is out of whack, the form submission is 
cancelled. 



LISTING 17-5 



Date Validation in a Form 

HTML: jsb-17-05.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Date Entry Val i dati on</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb- 17 -05 . j s "></scri pt> 

</head> 

<body> 

<hl>Date Entry Val i dati on</hl> 

<form i d="bi rthdate" acti on="exampl e . php" method="post"> 
<p>Please enter your bi rthdate ... </p> 
<P> 

< 1 a be 1 f or=" month ">Month:</label> 

<input type="text" id="month" name="month " value="l" size="2" 
maxl ength="2"> 

<label for="day">Day :</! abel > 

<input type="text" id="day" name="day" value="l" size="2" 
maxl ength="2"> 

< 1 abel for="year">Year:</label> 

<input type="text" id="year" name="year" value="1900" size="4" 
maxl ength="4"> 

</p> 

<p>Thank you for entering <span i d="f ul 1 Date">your bi rthdate</span> . </p> 

<P> 

<input type="submi t"> 



304 



Chapter 17: The Date Object 



<input type="Reset"> 

</p> 
</ form) 
</body> 
</html > 



JavaScript: jsb-17-05.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 



f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// point to the target elements 

oForm = document . getEl ementBy Id (' bi rthdate ') ; 

oMonth = document . getEl ementBy Id (' month ') ; 

oDay = document . getEl ementBy Id (' day ') ; 

oYear = document . getEl ementBy Id ( 'year ') ; 

oFullDate = document . getEl ementBy Id (' ful I Date ') ; 



// if they exist, plug in new content 

if (oForm && oMonth && oDay && oYear && oFullDate) 

{ 

// apply behaviors to form elements 
oForm . onsubmi t = checkForm; 

oMonth . onchange = functionO ( return val i dateMonth ( oMonth ) ; ( 
oDay . onchange = functionO { return val i dateDay ( oDay ) ; ) 
oYear . onchange = functionO ( return val idateYear(oYear) ; ) 

I 



function checkForm(evt) 
{ 

if ( val i dateMonth ( oMonth ) ) 
{ 

if (val idateDay(oDay) ) 
{ 

if (val idateYear(oYear) ) 
{ 

// do nothing 

I 

I 

) 

return false; 

I 



// validate input month 

function val i dateMonth ( oFi el d , bBypassUpdate ) 

continued 

305 



Part III: JavaScript Core Language Reference 



LISTING 17-5 



(continued) 



var slnput = oFi el d . val ue ; 

if ( i sEmpty ( s I nput ) ) 
{ 

alert("Be sure to enter a month value."); 
sel ect Fi eld(oField) ; 
return false; 



el se 



slnput = parsel nt ( oFi el d . val ue , 10); 
if CisNaN(sInput)) 
{ 

al ert ( " Entri es must be numbers only."); 
sel ect Fi el d ( oFi el d ) ; 
return false; 

} 

else 
{ 

if ( ! i nRange ( s I nput , 1 , 12 ) ) 
{ 

alert("Enter a number between 1 (January) and 12 (December).") 
sel ect Fi el d ( oFi el d ) ; 
return false; 



I 

if ( ! bESypassllpdate ) 
{ 

cal cDate( ) ; 

1 

return true; 

} 

// val i date i nput day 
function val i dateDay ( oFi el d ) 
{ 

var slnput = o Fi el d . val ue ; 

if ( i sEmpty ( s I nput ) ) 
{ 

alert("Be sure to enter a day value.") 
sel ect Fi el d ( oFi el d ) ; 
return false; 

} 

else 
{ 

slnput = parsel nt ( o Fi el d . val ue , 10); 



306 



Chapter 17: The Date Object 



if (isNaN(sInput)) 
{ 

al ert ( " Entri es must be numbers only."); 
sel ect Fi el d ( oFi el d ) ; 
return false; 

} 

el se 
{ 

var monthField = oMonth; 

if (! val i dateMonth (month Fi el d , true)) 
return false; 

var iMonthVal = parsel nt (month Fi el d . val ue , 10); 

var iMonthMax = new Array ( 31 , 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ) ; 
var iTop = iMonthMax[iMonthVal ] ; 

if ( ! i nRange ( s I nput , 1 , i Top ) ) 
{ 

alert("Enter a number between 1 and " + iTop + "."); 

sel ect Fi el d ( oFi el d ) ; 
return false; 



cal cDate( ) ; 
return true; 

} 

// val i date i nput year 
function val i dateYear ( oFi el d ) 
{ 

var iCurrentYear = (new Date ). get Ful 1 Year () ; 

var slnput = o Fi el d . val ue ; 
if ( i sEmpty ( s I nput ) ) 
{ 

alert("Be sure to enter a year value."); 
sel ect Fi el d ( oFi el d ) ; 
return false; 

} 

el se 
( 

slnput = parsel nt ( oFi el d . val ue , 10); 
if (isNaN(sInput)) 
{ 

al ert( "Entries must be numbers only."); 
sel ect Fi el d ( oFi el d ) ; 
return false; 

} 

el se 
{ 

if (! i nRange ( s I nput , 1900, iCurrentYear)) 

continued 



307 



Part III: JavaScript Core Language Reference 



LISTING 17-5 



(continued) 



{ 

al ert( "Enter a number between 1900 and " + iCurrentYear + "."); 
sel ect Fi eld(oField) ; 
return false; 

) 



cal cDate( ) ; 
return true; 

} 

// place the edit cursor in the requested field 

function sel ect Fi el d ( o Fi el d ) 

{ 

oFi el d . focus ( ) ; 
oFi el d . sel ect{ ) ; 

} 

// format a complete date 

functi on cal cDate( ) 

{ 

var mm = parsel nt ( oMonth . val ue , 10); 
var dd = parsel nt ( oDay . val ue , 10); 
var yy = parsel nt ( oYear . val ue , 10); 
sDate = mm + " / " + dd + " / " + yy ; 
repl aceTextContent(oFul 1 Date, sDate); 

} 

// **BEGI N GENERIC VALIDATION FUNCTIONS** 

// general purpose function to see if an input value has been entered at all 

function i sEmpty ( s I nput ) 

{ 

if (slnput == "" || slnput == null) 
! 

return true; 

1 

return false; 

} 

// determine if value is in acceptable range 

function i nRange ( s I nput , iLow, iHigh) 

{ 

var num = parselnt(slnput, 10); 

if (num < iLow || num > iHigh) 
{ 

return false; 

1 

return true; 

} 

// **END GENERIC VALIDATION FUNCTIONS** 



308 



Chapter 17: The Date Object 



As a general rule, JavaScript validation is only the first line of defense and must be backed up by 
server-side validation using PHP or another server scripting language. Because some users and user 
agents are going to be running without JavaScript, the server-side program will need to perform the 
validation all over again, but for those using JavaScript the validation feedback will be immediate. 

Not every date entry validation must be divided in this way. For example, an intranet application can 
be more demanding in the way users are to enter data. Therefore, you can have a single field for date 
entry, but the parsing required for such a validation is quite different from that shown in Listing 17-5. 
See Chapter 46 on the CD-ROM for an example of such a one-field date validation routine. 

Data entry validation is also an area of scripting that can benefit from asynchronous JavaScript, also 
known as Ajax, when it's necessary to look up values on the server to validate input. However, the 
advantages should be considered carefully since every Ajax operation requires a round-trip to the 
server and might not be any faster than submitting the whole page. 

Cross-Reference 

Check out Chapter 39, "Ajax, E4X, and XML," for more on how Ajax can be used to carry out dynamic data 
entry validation. ■ 



309 



The Array Object 




An array is one of the major JavaScript structures provided for storing 
and manipulating ordered collections of data. But unlike some other pro- 
gramming languages, JavaScript's arrays are very forgiving as to the kind 
of data you store in each cell or entry of the array. This allows, for example, an 
array of arrays, providing the equivalent of multidimensional arrays customized 
to the kind of data your application needs. 

If you have not done a lot of programming in the past, the notion of arrays may 
seem like an advanced topic. But if you ignore their capabilities, you set your- 
self up for a harder job when implementing many kinds of tasks. Whenever we 
approach a script, one of our first thoughts is about the data being controlled by 
the application and whether handling it as an array will offer some shortcuts for 
creating the document and handling interactivity with the user. 

We hope that by the end of this chapter you will not only be familiar with the 
properties and methods of JavaScript arrays but you will also begin to look for 
ways to make arrays work for you. 



IN THIS CHAPTER 



Working with ordered 
collections of data 

Simulating multidimensional 
arrays 

Manipulating information 
stored in an array 

New additions to JavaScript 
array handling 



Structured Data 



In programming, an array is defined as an ordered collection of data. 

You can best visualize an array as a table, not much different from a spreadsheet. 

In JavaScript, arrays are limited to a table holding one column of 

data, with as many rows as needed to hold your data. As you have seen in many 

chapters in Part IV, a JavaScript-enabled browser creates a number of internal 

arrays for the objects in your HTML documents and browser properties. For 

example, if your document contains five links, the browser maintains a table of 

those links. You access them by number (with 0 being the first link) in the array 

syntax: the array name is followed by the index number in square brackets, as in 

document . 1 inks [0], which represents the first link in the document. 

For many JavaScript applications, you will want to use an array as an organized 
warehouse for data that users of your page access, depending on their interaction 



311 



Part III: JavaScript Core Language Reference 



with form elements. In the application shown in Chapter 53, "Application: A Lookup Table" on the 
CD-ROM, for example, we demonstrate an extended version of this usage in a page that lets users 
search a small table of data for a match between the first three digits of their U.S. Social Security num- 
bers and the state in which they registered with the agency. Arrays are one way JavaScript-enhanced 
pages can re-create the behavior of more sophisticated server-side applications such as CGI scripts and 
Java servlets. When the collection of data you embed in the script is no larger than a typical . g i f 
image file, the user won't experience significant delays in loading your page; yet he or she has the 
full power of your small database collection for instant searching without any calls back to the server. 
Such database-oriented arrays are important applications of JavaScript for what we call serverless CGIs. 

As you design an application, look for clues as to potential uses of arrays. If you have a number 
of objects or data points that interact with scripts the same way, you have a good candidate for 
array structures. For example, you can assign like names to every text field in a column of an 
order form. In that sequence, like-named objects are treated as elements of an array. To perform 
repetitive row calculations down an order form, your scripts can use array syntax to perform all 
the extensions within a handful of JavaScript statements, rather than perhaps dozens of state- 
ments hard-coded to each field name. Chapter 54, "Application: A 'Poor Man's' Order Form" 
(on the CD-ROM) shows an example of this application. 

You can also create arrays that behave like the Java hash table: a lookup table that gets you to a 
desired data point instantaneously if you know the name associated with the entry. 

If you can somehow conceive your data in a table format, an array is in your future. 

Creating an Empty Array 

Full-fledge array objects in JavaScript go all the way back to NN3 and IE4. It was possible to simu- 
late some array characteristics in even earlier browsers, but since those first-generation browsers have 
thankfully disappeared from most users' computers, this chapter focuses on the modem array and its 
hefty powers. 

To create a new array object, use the static Array object's constructor method. For example: 

var myArray = new ArrayO; 
An array object automatically has a length property (0 for an empty array). 

Should you want to presize the array (for example, preload entries with null values), you can specify 
an initial size as a parameter to the constructor. For example, here is how to create a new array to 
hold information about a 500-item compact disc collection: 

var myCDCol 1 ecti on = new Array(500); 

Unlike with many other programming languages, presizing a JavaScript array does not give 
you any particular advantage, because you can assign a value to any slot in an array at any 
time: The length property adjusts itself accordingly. For instance, if you assign a value to 
myCDCol 1 ecti o n [ 7 0 0 ] , the array obj ect adjusts its length upward to meet that slot (with the count 
starting at 0): 

myCDCol 1 ecti on [700] = "The Smi ths/ Louder Than Bombs"; 
collect ionSize = my CDCollect ion. length; // result = 701 

Since the count of array elements starts at 0, assigning a value to location 700 results in an array that 
contains 701 items. 



312 



Chapter 18: The Array Object 



A true array object features a number of methods and the capability to add prototype properties, 
described later in this chapter. 



Populating an Array 

Entering data into an array is as simple as creating a series of assignment statements, one for each 
element of the array. Listing 18-1 generates an array containing a list of the eight planets of the solar 
system. 



LISTING 18-1 



Generating and Populating a New Array 

solarSys = new Array(); 

solarSys[0] = "Mercury"; 

solar Sys[l] = "Venus"; 

solar Sys[2] = "Earth"; 

solar Sys[3] = "Mars"; 

solar Sys[4] = "Jupiter"; 

solar Sys[5] = "Saturn"; 

solar Sys[6] = "Uranus"; 

solar Sys[7] = "Neptune"; 



This way of populating a single array is a bit tedious when you're writing the code, but after the array 
is set, it makes accessing collections of information as easy as any array reference: 

onePlanet = solarSys[4]; // result = "Jupiter" 

A variant of this method takes advantage of the fact that, because JavaScript arrays are zero-based, 
the array length property always points past the end of the array at the next item to be filled. The 
following code produces an array identical to the one above: 

solarSys = new ArrayO; 

sol a rSys [ sol a rSy s . 1 ength ] = "Mercury"; 

solar SysfsolarSys. length] = "Venus"; 

solar SysfsolarSys. length] = "Earth"; 

solar SysfsolarSys. length] = "Mars"; 

solar SysfsolarSys. length] = "Jupiter"; 

solar SysfsolarSys. length] = "Saturn"; 

solar SysfsolarSys. length] = "Uranus"; 

solar SysfsolarSys. length] = "Neptune"; 

This makes sense if you think about it: a newly created empty array has a length of zero, and the 
first item to be added to it is array[0]. The length is then one and the next item to be added is 
array [1]; and so on. 

Assigning array elements like this makes it easy to edit the script later to add or remove elements 
without having to change all the subsequent subscripts: 

solarSys = new ArrayO; 

sol a rSys [ sol a rSy s . 1 ength ] = "Mercury"; 

313 



Part III: JavaScript Core Language Reference 



solar Sys[solarSys. length] = "Venus"; 

sol a rSys [ sol a rSys . 1 ength ] = "Earth"; 

sol a rSys [ sol a rSys . 1 ength ] = "Mars"; 

sol a rSy s [ sol a rSys . 1 engt h ] = "asteroid belt"; 

solar Sys[solarSys. length] = "Jupiter"; 

solar Sys[solarSys. length] = "Saturn"; 

solar Sys[solarSys. length] = "Uranus"; 

sol a rSys [ sol a rSys . 1 ength ] = "Neptune"; 

A more compact way to create an array is available if you know that the data will be in the desired 
order (such as the preceding sol arSys array). Instead of writing a series of assignment statements (as 
in Listing 18-1), you can create what is called a dense array by supplying the data as comma-delimited 
parameters to the Array ( ) constructor: 

solarSys = rew Array ( "Mercury" , "Verus" ," Earth" , "Mars" , "Jupi ter" , "Saturn" , 
"Uranus" , "Neptune" ) ; 

The term "dense array" simply means that data is packed into the array, without gaps, starting at index 
position 0. 

The example in Listing 18-1 shows what you may call a vertical collection of data. Each data point 
contains the same type of data as the other data points — the name of a planet — and the data points 
appear in the relative order of the planets from the Sun. 



JavaScript Array Creation Enhancements 

JavaScript provides one more way to create a dense array and also clears up a bug in the way older 
browsers handled arrays. This improved approach does not require the Array object constructor. 
Instead, JavaScript (as of version 1.2) accepts what is called literal notation to generate an array. To 
demonstrate the difference, the following statement is the regular dense array constructor that works 
all the way back to NN3: 

solarSys = new Array ( "Mercury ", "Venus "," Earth" , "Mars" , "Jupi ter ", "Saturn" , 
"Uranus" , "Neptune" ) ; 

While JavaScript 1.2+ fully accepts the preceding syntax, it also accepts the new literal notation: 

sol a rSy s = [ "Mercury "," Venus "," Ea rth ", "Ma rs ", "Jupi ter "," Saturn " , 
"Uranus" , "Neptune"] ; 

The square brackets stand in for the call to the Array constructor. If you use this streamlined 
approach to array creation, be aware that it may stop JavaScript execution cold in old browsers. 

The bug fix we mentioned has to do with how to treat the earlier dense array constructor if the 
scripter enters only the numeric value 1 as the parameter — new Array(l).In NN3 and IE4, 
JavaScript erroneously creates an array of length 1, but that element is undefined. For NN4 and 
all later browsers, the same statement creates that one-element array and places the value 1 in that 
element. 



314 



Chapter 18: The Array Object 



Deleting Array Entries 

You can easily wipe out any data in an array element by setting the value of the array entry to null 
or an empty string. But until the delete operator came along in version 4 browsers, you could not 
completely remove an element. 

Deleting an array element eliminates the index from the list of accessible index values but does not 
reduce the array's length, as in the following sequence of statements: 

myArray . I ength // result: 5 
delete myArray[2] 

myArray . I ength // result: 5 

myArray[2] // result: undefined 

The process of deleting an array entry does not necessarily release memory occupied by that data. The 
JavaScript interpreter's internal garbage collection mechanism (beyond the reach of scripters) is sup- 
posed to take care of such activity. See the delete operator in Chapter 22, "JavaScript Operators," 
for further details. 

If you want tighter control over the removal of array elements, you might want to consider using 
the spl i ce( ) method, which is supported in modem browsers. The spl i ce( ) method can be 
used on any array and lets you remove an item (or sequence of items) from the array — causing 
the array's length to adjust to the new item count. See the spl i ce( ) method later in this 
chapter. 



Parallel Arrays 

Using an array to hold data is frequently desirable so that a script can do a lookup to see if a par- 
ticular value is in the array (perhaps verifying that a value typed into a text box by the user is per- 
missible); however, even more valuable is if, upon finding a match, a script can look up some related 
information in another array. One way to accomplish this is with two or more parallel arrays: the same 
indexed slot of each array contains related information. 

Consider the following three arrays: 

var regi onal Of f i ces = ["New York", "Chicago", "Houston", "Portland"]; 
var regi onal Managers = ["Shirley Smith", "Todd Gaston", 

"Leslie Jones", "Harold Zoot"]; 
var regOffi ceQuotas = [300000, 250000, 350000, 225000]; 

The assumption for these statements is that Shirley Smith is the regional manager out of the New York 
office, and her office's quota is 300,000. This represents the data that is included with the document, 
perhaps retrieved by a server-side program that gets the latest data from a SQL database and embeds 
the data in the form of array constructors. Listing 18-2 shows how this data appears in a simple page 
that looks up the manager name and quota values for whichever office is chosen in the sel ect ele- 
ment. The order of the items in the list of select is not accidental: the order is identical to the order 
of the array for the convenience of the lookup script. 



315 



Part III: JavaScript Core Language Reference 



Lookup action in Listing 18-2 is performed by the get Data ( ) function. Because the index values of 
the options inside the select element match those of the parallel arrays index values, the sel ecte- 
d I ndex property of the select element makes a convenient way to get directly at the corresponding 
data in other arrays. 

Cross-Reference 

The property assignment event-handling technique employed throughout the code in this chapter and 
much of the book is addEvent( ), a cross-browser event handler explained in detail in Chapter 32, 
"Event Objects." 

The add Event ( ) function is part of the script file jsbglobal .js located on the accompanying CD-ROM 
in the Content / folder where it is accessible to all chapters' scripts. ■ 



LISTING 18-2 



A Simple Parallel Array Lookup 

HTML: jsb-18-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Paral 1 el Array Lookup</ti tl e> 

<script type=" text /javascript" src="../jsb-global . js "></scn'pt> 
<script type="text/ j avascri pt" src="j sb- 18-02 . j s "></scri pt> 

</head> 

<body> 

<hl>Parallel Array Lookup</hl> 

<form i d="of f i ceData " action="" method="post"> 

<P> 

< 1 a be 1 for="off i ces">Sel ect a regional of f i ce : </l abel > 
<select id="offices" name="off i ces"> 
</sel ect> 

</p> 
<P> 

< 1 abel f or="manager">The manager i s : < / 1 a be 1 > 

<input type="text" id="manager" name="manager" size="35" /> 

</p> 
<P> 

< 1 abel for="quota">The office quota i s : < / 1 a be 1 > 
<input type="text" id="quota" name="quota " size="8" /> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1802.js 

// initialize when the page has loaded 
addEvent(window, 'load', initialize); 



316 



Chapter 18: The Array Object 



f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// set up the data in global variables (by omitting 'var') 

aRegi onal Of f i ces = ["New York", "Chicago", "Houston", "Portland"]; 

aRegi onal Managers = ["Shirley Smith", "Todd Gaston", "Leslie Jones", 

"Harol d Zoot"] ; 
aRegOfficeQuotas = [300000, 250000, 350000, 225000]; 

// point to the critical input fields & save in global variables 
oSelect = document . getEl ementBy Id (' of fi ces ') ; 
oManager = document . getEl ementBy Id( ' manager ') ; 
oQuota = document . getEl ementBy Id (' quota ') ; 

// if they al I exi st . . . 

if (oSelect && oManager && oQuota) 

{ 

// build the drop-down list of regional offices 
for (var i = 0; i < aRegi onal Of f i ces . I ength ; i++) 
{ 

oSel ect . opti ons [ i ] = new Opti on ( aRegi onal Of fi ces [ i ]) ; 

} 

// set the onchange behavior 
addEvent ( oSel ect , 'change', getData); 

) 

// plug in data for the default select option 
getData ( ) ; 

I 

I 



// when a new option is selected, do the lookup into parallel arrays 

function getData(evt) 

{ 

// get the offset of the selected option 
var index = oSel ect . sel ectedl ndex ; 

// get data from the same offset in the parallel arrays 
oManager . val ue = aRegi onal Managers[i ndex] ; 
oQuota. value = aRegOff i ceQuotas[i ndex] ; 



On the other hand, if the content to be looked up is typed into a text box by the user, you have to 
loop through one of the arrays to get the matching index. Listing 18-3 is a variation of Listing 18-2, 
but instead of the select element, a text field asks users to type in the name of the region. Assum- 
ing that users will always spell the input correctly (admittedly an outrageous assumption), the version 
of getData( ) in Listing 18-3 performs actions that more closely resemble what you may think a 
"lookup" should be doing: looking for a match in one array, and displaying corresponding results 
from the parallel arrays. The for loop iterates through items in the aRegi onal Off i ces array. An 



317 



Part III: JavaScript Core Language Reference 



i f condition compares all uppercase versions of both the input and each array entry. If there is a 
match, the for loop breaks, with the value of i still pointing to the matching index value. Outside 
the for loop, another i f condition makes sure that the index value has not reached the length of 
the array, which means that no match is found. Only when the value of i points to one of the array 
entries does the script retrieve corresponding entries from the other two arrays. 



LISTING 18-3 



A Looping Array Lookup 



HTML: jsb-18-03.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 

<titl e>Paral 1 el Array Lookup IK/title> 

<script type="text/ j avascri pt" src="../jsb- 

<script type="text/ j avascri pt" src="jsb-18- 
</head> 
<body> 

<hl>Parallel Array Lookup IK/hl> 



-gl obal . j s "></scri pt> 
-03 . j s "></scri pt> 



<form id 
<P> 

<1 abel 
<i nput 
<i nput 

</p> 
<P> 

<1 abel 
<i nput 

</p> 
<P> 

<1 abel 
<i nput 

</p> 
</ form) 
</body> 
</html > 



officeData" action= 



f or="of f i celnput' 
i d="of f i celnput" 
i d="of f i ceSearch' 



" method="post"> 

>Enter a regional 
name="off i celnput' 
type="button" va" 



of f i ce : </l abel > 

si ze="35"> 
ue="Search"> 



f or="manager">The manager i s : < / 1 a be 1 > 



type="text" id="manager" 



'manager" size="35" /> 



for="quota">The office quota i s : < / 1 a be 1 > 
type="text" id="quota" name="quota" size= 



'8" /> 



JavaScript: jsb-18-03.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

// set up the data in global variables (by omitting 'var') 



318 



Chapter 18: The Array Object 



aRegi onal Of f i ces = ["New York", "Chicago", "Houston", "Portland"]; 
aRegi onal Managers = ["Shirley Smith", "Todd Gaston", "Leslie Jones", 

"Harol d Zoot"] ; 
aRegOfficeQuotas = [300000, 250000, 350000, 225000]; 

// point to the critical input fields & save in global variables 
oOffice = document . getEl ementBy Id (' of fi eel nput ') ; 
oSearch = document . getEl ementBy Id( ' of fi ceSearch ') ; 
oManager = document . getEl ementBy Id( ' manager ') ; 
oQuota = document . getEl ementBy Id (' quota ') ; 

// if they al I exi st . . . 

if (oOffice && oSearch && oManager && oQuota) 
{ 

// apply behavior to the search button 
addEvent ( oSearch , 'click', getData); 

) 

I 

} 

// when the Search button is clicked, do the lookup into parallel arrays 

function getData(evt) 

{ 

// make a copy of the text box contents 
var slnputText = oOf f i ce . val ue ; 

// nothing entered? 
if ( ! s I nputText ) 
{ 

al ert( ' PI ease enter an office location.'); 

} 

el se 
{ 

// loop through all entries of regi onal Of f i ces array 
for (var i = 0; i < aRegi onal Of f i ces . I ength ; i++) 
{ 

// compare entered text against each item in regi onal Of fi ces 
// (make both uppercase for easy comparison) 

if (slnputText. toUpperCase( ) == aRegi onal Of fi ces [ i ]. toUpperCase () ) 
{ 

// if they're the same, then break out of the for loop 
break; 



// make sure the i counter hasn't exceeded the max index value 

if (i < aRegi onal Of fi ces . I ength ) 

{ 

// display corresponding entries from parallel arrays 
oManager . val ue = aRegi onal Managers[i ] ; 
oQuota. value = aRegOff i ceQuotas[i ] ; 

) 

// otherwise the loop went all the way with no matches 

continued 



319 



Part III: JavaScript Core Language Reference 



LISTING 18-3 



(continued) 



el se 



// empty any previous values 
oManager . val ue = ""; 
oQuota. value = ""; 

// advise user 

alert("No match found for '" + slnputText + 



// return the focus to the office input field 
oOf f i ce . f ocus ( ) ; 



Multidimensional Arrays 



An alternate to parallel arrays is the simulation of a multidimensional array. While it's true that 
JavaScript arrays are one-dimensional, you can create a one-dimensional array of arrays or other 
objects. A logical approach is to make an array of custom objects, because the objects easily allow 
for naming of object properties, making references to multidimensional array data more readable. 
(Custom objects are discussed at length in Chapter 23, "Function Objects and Custom Objects." See 
also Chapter 19, "JSON -Native JavaScript Object Notation.") 

Using the same data from the examples of parallel arrays, the following statements define an object 
constructor for each "data record." A new object is then assigned to each of four entries in the main 
array. 

// custom object constructor 

function officeRecord(city, manager, quota) 

{ 

this, city = city; 
this. manager = manager; 
thi s .quota = quota ; 



// create new main array 

var regionalOffices = new Array(); 

// stuff main array entries with objects 

regionalOfficesfO] = new of f i ceRecordt "New York", "Shirley Smith", 300000); 
regionalOfficesfl] = new officeRecord( "Chicago" , "Todd Gaston", 250000 ); 
regional0ffices[2] = new off i ceRecord( "Houston" , "Leslie Jones", 350000); 
regional0ffices[3] = new of fi ceRecordt " Portl and" , "Harold Zoot", 225000 ); 

The object constructor function (officeRecord( )) assigns incoming parameter values to properties 
of the object. Therefore, to access one of the data points in the array, you use both array notations to 
get to the desired entry in the array and the name of the property for that entry's object: 



320 



Chapter 18: The Array Object 



var eastOf f i ceManager = regi onal Of fi ces [0] . manager ; 
You can also assign string index values for this kind of array, as in: 

regionalOffices["east"] = new of f i ceRecord( "New York", "Shirley Smith", 
300000) ; 



and access the data via the same index: 



var eastOffi ceManager = regi onal Of fi ces [ "east "]. manager ; 

But if you're more comfortable with the traditional multidimensional array (from your experience in 
other programming languages), you can also implement the above as an array of arrays with less code: 



// create new main array 

var regi onal Of fi ces = new Array( 

// stuff main array entries with 



regi onal Off i ces[0] = new Array(' 

regi ona I Of f i ces [ 1 ] = new Array(' 

regi onal Of fi ces [2] = new Array(' 

regi onal Of fi ces [3] = new Array(' 



arrays 
New York" 
Chicago" , 
Houston" , 
Portland" 



"Shi rl ey Smith" , 300000) ; 
'Todd Gaston" , 250000) ; 



' Lesl i e Jones' 
"Harold Zoot' 



350000) 
225000) 



or with the extreme brevity of literal notation: 



// create new main array 
var regi onal Of fi ces = [ 

["New York", "Shirley Smith", 300000], 
["Chicago", "Todd Gaston", 250000], 
["Houston", "Leslie Jones", 350000], 
["Portland", "Harold Zoot", 225000] 

] ; 

Accessing a single data point of an array of arrays requires a double array reference. For example, 
retrieving the manager's name for the Houston office requires the following syntax: 

var HoustonMgr = regi onal Of f i ces [2] [ 1 ] ; 

The first index in brackets is for the outermost array (regi onal Off ices); the second index in 
brackets points to the item of the array returned by regiona!0ffices[2]. 



Simulating a Hash Table 

Nearly all arrays shown so far in this chapter have used integers as their index values. A JavaScript 
array is a special type of object (the object type is covered in Chapter 23, "Function Objects and 
Custom Objects"). As a result, you can also assign values to customized properties of an array with- 
out interfering with the data stored in the array or the length of the array. In other words, you can 
"piggy-back" data in the array object. You may reference the values of these properties either using 
"dot" syntax (array . property Name) or through array-looking syntax consisting of square brack- 
ets and the property name as a string inside the brackets (array["propertyName"]). An array 
used in this fashion is also known as an associative array. If you use the dot syntax, then you can't 
use characters such as hyphens, spaces, periods, and quotation marks in the propertyName values 



321 



Part III: JavaScript Core Language Reference 



whereas the only limitation on the quoted bracket syntax is that the values not contain the same type 
of quotation marks as you're using to quote the expressions. 

These do not work: 

// Dot notation: 

oArray. Chris Smith // space 

oArray . Ch r i s -Smi th // hyphen 

oArray . Ch ri s . Smi th // period 

oArray . Smi th , Chri s // comma 

oArray . Ch ri s " Pun ky " Smi th // quotes 



// Quoted bracket notation: 
oArray [" Chri s "Punky" Smith"] 
oArray [' Chri s 'Punky' Smith'] 



// matching quotes 
// matching quotes 



These do work: 



// one word 
// underscore 



// Dot notation: 
oArray .Chri sSmi th 
oArray .Chri s_Smi th 

// Quoted bracket notation (nearly everything works): 
oArray["Chri s_Smi th " ] 
.Smith"] 
Smi th" ] 
Chris"] 

'Punky' Smith"] // 
"Punky" Smith'] // 



ur\ iiujl '-•lit I o_ 

oArray ["Chris. 
oArray ["Chris 
oArray [ " Smi th , 
oArray ["Chris 
oArray [ ' Chri s 



non-matching quotes 
non-matching quotes 



Addressing object properties by way of string indexes is sometimes very useful. For example, the mul- 
tidimensional array described in the previous section consists of four objects. If your page contains a 
form whose job is to look through the array to find a match for a city chosen from a select list, the 
typical array lookup would loop through the length of the array, compare the chosen value against 
the ci ty property of each object, and then retrieve the other properties when there was a match. For 
a four-item list, this isn't a big deal. But for a 100-item list, the process could get time consuming. 
A faster approach would be to jump directly to the array entry whose ci ty property is the chosen 
value. That's what a simulated hash table can do for you (some programming languages have formal 
hash table constructions especially designed to act like a lookup table). 

Create a simulated hash table after the array is populated by looping through the array and assign- 
ing properties to the array object as string values. Use string values that you expect to use for lookup 
purposes. For example, after the regi onal Of f i ces array has its component objects assigned, run 
through the following routine to make the hash table: 

for (var i = 0; i < regi onal Of fi ces . 1 ength ; i++) 

{ 

regionalOffices[regionalOffices[i].city] = regionalOffices[i]; 



You can retrieve the manager property of the Houston office object as follows: 
var HoustonMgr = regi onal Of fi ces [" Houston "]. manager ; 



322 



Chapter 18: The Array Object 



arrayObject 

With the aid of the hash table component of the array, your scripts have the convenience of 
both numeric lookup (if the script needs to cycle through all items) and an immediate jump to 
an item. 

Cross-Reference 

For more ways to represent data structures in JavaScript, see Chapters 1 9 and 20. ■ 

Array Object 

Properties Methods 

constructor concat() 
length every()* 
prototype filter()* 

forEach( )* 

indexOf ( )* 

joint ) 

1 astlndexOf ( )* 

map( )* 

pop( ) 

push ( ) 
reduce( ) 
reduceRi ght( ) 
reverse( ) 

shift( ) 

si i ce( ) 
someC )* 
sort( ) 
spl i ce( ) 

toLocal eStri ng( ) 
toStri ng( ) 
unshif t( ) 



*ltems marked with an asterisk in the list of Array object properties and methods are relatively recent additions 
with JavaScript 1.6 and later. They are supported by Mozilla browsers such as Firefox 2.0+ but not by Internet 
Explorer as of version 8, which has a browser market share too large to ignore. We have provided code in this 
chapter that adds these new methods to the Array object if they don't already exist. 



323 



Part III: JavaScript Core Language Reference 



arrayObject.constructor 

Array object properties 

constructor 

(See string . constructor in Chapter 15, "The String Object") 

1 ength 

Value: Integer Read/Write 

Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari+, Opera+, Chrome+ 

A true array object's 1 ength property reflects the number of entries in the array. An entry can 
be any kind of JavaScript value, including null. If an entry is in the 10 th cell and the rest are 
null, the length of that array is 1 0 . Note that because array index values are zero-based, the 
index of the last cell of an array is one less than the length (9 in this case). This characteristic 
makes it convenient to use the property as an automatic counter to append a new item to an 
array: 

myArray [myArray . 1 ength] = val ueOfAppendedltem; 

Thus, a generic function does not have to know which specific index value to apply to an additional 
item in the array. 

prototype 

Value: Variable or function Read/Write 
Compatibility: WinIE4+, MacIE44-, NN34-, Moz4-, Safari 4-, Opera4-, Chrome + 

Inside JavaScript, an array object has its dictionary definition of methods and length 
property — items that all array objects have in common. The prototype property enables 
your scripts to ascribe additional properties or methods that apply to all the arrays you create in the 
currently loaded documents. You can override this prototype, however, for any individual object. 

Example 

To demonstrate how the prototype property works, Listing 18-4 creates a prototype property for 
all array objects generated from the static Array object. As the script generates new arrays (instances 
of the Array object, just as a date object is an instance of the Date object), the property automati- 
cally becomes a part of those arrays. In one array, c, you override the value of the prototype sponsor 
property. By changing the value for that one object, you don't alter the value of the prototype for the 
Array object. Therefore, another array created afterward, d, still gets the original sponsor property 
value. 



LISTING 18-4 



Adding a prototype Property 

HTML: jsb-18-04.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ;charset=utf-8"> 



324 



Chapter 18: The Array Object 



arrayObjeclprototype 

<title>Array prototypes</title> 

<script type=" text/ javascript" src="jsb-18-04.js"X/script> 
</head> 
<body> 

<hl>Array prototypes</hl> 
</body> 
</html > 

JavaScript: jsb-18-04.js 

// add prototype to all Array objects 
Array . prototype . sponsor = "DG"; 

// create new arrays 
var a = new Array ( ) ; 
var b = new Array ( ) ; 
var c = new Array ( ) ; 

// override prototype property for one 'instance' 
c. sponsor = "JS"; 

// this one picks up the original prototype 
var d = new Array ( ) ; 

// display results 

var sMsg = "Array a is brought to you by: " + a. sponsor + "\n"; 

sMsg += "Array b is brought to you by: " + b. sponsor + "\n"; 

sMsg += "Array c is brought to you by: " + c. sponsor + "\n"; 

sMsg += "Array d is brought to you by: " + d. sponsor; 
al ert ( sMsg ) ; 



You can assign properties and functions to a prototype. To assign a function, define the function as 
you normally would in JavaScript. Then assign the function to the prototype by name: 

function newFunc(paraml) 

{ 

// statements 

) 

Array . prototype . newMethod = newFunc; // omit parentheses in this reference 

where newMethod is whatever you want to name the method (the function name will not be 
retained). 

When you need to call upon that function (which has essentially become a new temporary method for 
the Array object), invoke it as you would any object method. Therefore, if an array named CDCol - 
1 ecti on has been created and a prototype method showCoverImage( ) has been attached to the 
array, the call to invoke the method for a tenth listing in the array is 

CDCollection.showCoverImage(9); 



325 



Part III: JavaScript Core Language Reference 



arrayObject.concatQ 

where the parameter of the function uses the index value to perhaps retrieve an image whose URL is a 
property of an object assigned to the 10 th item of the array. 



Array object methods 

After you have information stored in an array, JavaScript provides several methods to help you manage 
that data. These methods, all of which belong to array objects you create, have evolved over time, 
so pay close attention to browser compatibility if you're in need of supporting legacy (pre -version 4) 
browsers. 

array . concat( a rrayZ) 

Returns: Array object 

Compatibility: WinIE4+, MacIE44-, NN44-, Moz4-, Safari 4-, Opera4-, Chrome4- 

The array . concat( ) method allows you to join two array objects into a new, third array object. 
The action of concatenating the arrays does not alter the contents or behavior of the two original 
arrays. To join the arrays, you refer to the first array object to the left of the period before the method; 
a reference to the second array is the parameter to the method. For example: 

var arrayl = new Ar ray ( 1 , 2 , 3 ) ; 

var array2 = new Array( "a" , "b" , "c" ) ; 

var array3 = a rray 1 . concat ( a r ray2 ) ; 

// result: array with values 1 , 2 , 3 , " a " , "b" , " c " 

If an array element is a string or number value (not a string or number object), the values 
are copied from the original arrays into the new one. All connection with the original arrays 
ceases for those items. But if an original array element is a reference to an object of any kind, 
JavaScript copies a reference from the original array's entry into the new array; so, if you make 
a change to either array's entry, the change occurs to the object, and both array entries reflect the 
change to the object. 

Example 

Listing 18-5 is a bit complex, but it demonstrates both how arrays can be joined with the 
array. concat( ) method and how values and objects in the source arrays do or do not propagate 
based on their data type. The page is shown in Figure 18-1. 

After you load the page, you see readouts of three arrays. The first array consists of all string 
values; the second array has two string values and a reference to a form object on the page 
(a text box named "original" in the HTML). In the initialization routine of this page, not only are the 
two source arrays created, but they are joined with the array. con cat ( ) method, and the result is 
shown in the third box. To show the contents of these arrays in columns, we use the array. jo in( ) 
method, which brings the elements of an array together as a string delimited in this case by a return 
character — giving us an instant column of data. 

Two series of fields and buttons let you experiment with the way values and object references are 
linked across concatenated arrays. In the first group, if you enter a new value to be assigned to 
arrayThree[0], the new value replaces the string value in the combined array. Because regular 
values do not maintain a link back to the original array, only the entry in the combined array is 
changed. A call to showArrays ( ) proves that only the third array is affected by the change. 



326 



Chapter 18: The Array Object 



arrayObject.concatQ 



FIGURE 18-1 



Object references remain "alive" in a concatenated array. 



UU, HU JJ.UL1.U.I.U J,U III- 1 JlffiM 



pe E<ttl tfew **%<*t Bookmarts loots tif*f> 



Array 1'ruluij pi's 



More complex is the object relationship for this demonstration. A reference to the first text box of the 
second grouping has been assigned to the third entry of arrayTwo. After concatenation, the same 
reference is now in the last entry of the combined array. If you enter a new value for a property of the 
object in the last slot of arrayThree, the change goes all the way back to the original object — the 
first text box in the lower grouping. Thus, the text of the original field changes in response to the 
change of a r rayTh ree [ 5 ] . And because all references to that object yield the same result, the refer- 
ence in arrayTwo[2] points to the same text object, yielding the same new answer. The display of 
the array contents doesn't change, because both arrays still contain a reference to the same object (and 
the value attribute showing in the < i n p u t > tag of the column listings refers to the default value of 
the tag, not to its current algonthmically retrievable value shown in the last two fields of the page). 



LISTING 18-5 



Array Concatenation 

HTML: jsb-18-05.html 

<!D0CTYPE html> 
<html > 
<head> 

continued 



327 



Part III: JavaScript Core Language Reference 



arrayObject.concatQ 



LISTING 18-5 



(continued) 



<meta http-equi v="content-type" content="text/html ; charset=utf - 
<title>Array Prototypes</ti tl e> 

<link type="text/css " rel ="styl esheet" href ="j sb- 18-05 . ess "> 



gl obal . j s "></scri pt> 
05 . j s "></scri pt> 



<script type="text/ j avascri pt" src="../jsb- 

<script type="text/ j avascri pt" src="jsb-18- 
</head> 
<body> 

<hl>Array Prototypes</hl> 
<f orm> 

<fieldset id="arrays"> 

<legend>Arrays</legend> 

<P> 

<label>arrayOne</label> 

<textarea name="arrayl" cols="25" rows="6"X/textarea> 

</p> 
<P> 

< 1 a be 1 >arrayTwo</l abel > 

<textarea name="array2" cols="25" rows="6"X/textarea> 

</p> 
<P> 

<1 abel >arrayThree</l abel > 

<textarea name="array3" cols="25" rows="6"X/textarea> 
</p> 
</fieldset> 
<f i el dset> 

<1 egend>Array Value Control s</l egend> 
<P> 

< 1 abel cl ass="i nput" for="sourcel 



type="text" name="sourcel" 
id="buttonl" type="button" 



<i nput 

<i nput 
</p> 
<P> 

<1 abel >Current array0ne[0] i s : < / 1 a be 1 > 
<input id="resultl" type="text" disabled 

</p> 
<P> 

<1 abel >Current arrayThree[0] i s : < / 1 a be 1 > 
<input id="result2" type="text" disabled 

</p> 

</fieldset> 



>Enter new value for 

arrayThree[0] : </l abel > 
val ue=" Jerry "> 

val ue="Change arrayThree[0] "> 



'di sabl ed"> 



'di sabl ed"> 



<f i el dset> 

<1 egend>0bject Value Control s</l egend> 
<P> 

<1 abel >text0bj assigned to arrayTwo[2] : </l abel > 

<input type="text" name="ori gi nal " di sabl ed="di sabl ed"> 

</p> 
<P> 

< 1 abel cl ass = "i nput">Enter new value for arrayThree[5] : </l abel > 



328 



Chapter 18: The Array Object 



arrayObjectconcatQ 

<input type="text" name="source2" val ue="Phoebe"> 

<input i d="button2" type="button" val ue="Change arrayThree[5] . val ue"> 

</p> 
<P> 

<l abel >Current arrayTwo[2] . val ue i s : < / 1 a be I > 

<input type="text" name="resul t3" di sabl ed="di sabl ed"> 

</p> 
<P> 

<l abel >Current arrayThree[5] . val ue i s : < / 1 a be I > 

<input type="text" name="resul t4" di sabl ed="di sabl ed"> 

</p> 

</fieldset> 
<p cl ass="reset"> 

<input i d="buttonReset" type="button" val ue="Reset"> 

</p> 
</ form) 
</body> 
</html > 

JavaScript: jsb-18-05.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

// gl obal vari abl es 

var arrayOne, arrayTwo, arrayThree, textObj ; 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementBy Id ) 

{ 

form = document . forms [0] ; 

var oButton = document . getEl ementBy Id (' buttonl ') ; 
if (oButton) oButton . oncl i ck = updatel; 

oButton = document . getEl ementBy Id (' button2 ') ; 
if (oButton) oButton . oncl i ck = update2; 

oButton = document . getEl ementBy Id (' buttonReset ') ; 

if (oButton) oButton . oncl i ck = functionO ( I ocati on . rel oad( ) ; ); 

// populate arrays 

textObj = form. ori gi nal ; 

arrayOne = new Array ( "Jerry" , "Elaine", "Kramer"); 
arrayTwo = new Array (" Ross " , "Rachel", textObj); 
arrayThree = arrayOne. concat(arrayTwo) ; 

// perform initial update 
updatel ( ) ; 
update2( ) ; 

continued 



329 



Part III: JavaScript Core Language Reference 



arrayObject.concatQ 
UmfcjtKlf^UB^U (continued) 



showArrays ( ) ; 

) 

} 

// display current values of all three arrays 

function showArrays ( ) 

{ 

f orm . array 1 . val ue = arrayOne . j oi n ( " \n " ) ; 
form.array2.val ue = arrayTwo . j oi n ( " \n " ) ; 
form . array3 . val ue = arrayThree . j oi n ( " \n " ) ; 

} 

// change the value of first item in Array Three 

function updatel ( evt ) 

{ 

arrayThree[0] = form . sourcel . val ue ; 
form . resul tl . val ue = arrayOne[0]; 
form . resul tZ . val ue = arrayThree[0] ; 
showArrays ( ) ; 

} 

// change value of object property pointed to in Array Three 

function update2(evt) 

{ 

arrayThree[5] . val ue = form. source2. val ue; 
form . resul t3 . val ue = arrayTwo[2] . val ue ; 
form . resul t4 . val ue = arrayThree[5] . val ue ; 
showArrays ( ) ; 

} 

Stylesheet: jsb-18-05.css 



f i el dset 
! 

clear: 1 eft ; 
float: left; 
margin-bottom: lem; 
padding: .5em; 

1 

f i el dset#arrays p 
{ 

float: left; 
margin: 0 .5em; 

} 

f i el dset#arrays label 
{ 

di spl ay : block; 
text-al i gn : center ; 

} 



330 



Chapter 18: The Array Object 



arrayObject.someQ 

abel . i nput 

font-weight: bold; 
. reset 

clear: I eft ; 



Related Item: a r r a y . j o i n ( ) method 

array . every ( ca 1 lback[, thi sObject]) 
array. some(ca7 lback[ , thi sObject]) 

Returns: Boolean 

Compatibility: FF2+, Safari3+, Chromel+, Opera 9.5+, WinlE— , MacIE— 

e v e r y ( ) and s o m e ( ) let you test the elements of an array with a callback function of your choice . 
(A callback is a function that is passed as an argument to another function.) The difference between 
the two methods is that every ( ) returns true only if every array element tests true, while some( ) 
returns true if even one element tests true. The original array is not modified unless your callback 
function explicitly modifies it. 

The callback function can contain any logic you want but in this case is required to return a Boolean 
value (either true or f al se). It takes three arguments: the value of the array element being exam- 
ined, its index in the array, and a reference to the array object being traversed, every ( ) uses the 
callback to test each member of the array in turn until a false value is returned or the end of the array 
is reached, some ( ) uses the callback to test each member of the array until a true value is returned 
or the end of the array is reached. Note that if the array is empty, every ( ) will return true because 
it hasn't encountered a value that would test false! 

Here's a simple example that checks whether an array contains all positive numbers: 

function i sPosi ti ve( i Val ue , ilndex, aArray) 

{ 

return ( i Val ue > 0 ) ; 

) 

var a = new Array(5, 4, 3, 2, 1); 
var bResult = a . every ( i sPosi ti ve) ; 

// returns true because there are no non-positive elements 
bResult = a.some(isPositive) ; 

// returns true because there is at least one positive element 

a = [5, 4, 3, 2, 1, 0]; 

bResult = a.every(isPositive) ; 

// returns false because zero is non-positive 



331 



Part III: JavaScript Core Language Reference 



arrayObject.someQ 



bResult = a . some( i sPosi ti ve) ; 

// returns true because there is at least one positive element 



a = new Array ( ) ; 



bResult = a.every(isPositive) ; 

// returns true since there are no non-positive elements in an empty array! 
bResult = a . some( i sPosi ti ve) ; 

// returns false because there are no positive elements in an empty array 

The following example takes advantage of the callback function's other arguments to use other array 
elements to evaluate the current one. A Fibonacci sequence is one in which each number is the sum of 
the previous two. Of course, the first two numbers in the sequence are exceptions to this algorithm 
and are "hard-coded" as zero and one, but the rest are calculable: 

function i s Fi bonacci ( i Val ue , ilndex, aArray) 

{ 

swi ten ( i Index ) 
{ 

case 0: 

return ( i Val ue == 0 ) ; 
break ; 



case 1: 

return ( i Val ue == 1 ) ; 
brea k ; 



def aul t : 

return (iValue == aArray[i Index-2] + aArray [i Index-1] ) ; 



var a = new Array(0, 1, 1, 2, 3, 5, 8, 13, 21); 
var bResult = a. eve ry(isFi bonacci); 
// returns true 



a = [0, 1, 1, 2, 3, 5, 8, 13, 22]; 

var bResult = a. eve ry ( i s Fi bonacci); 

// returns false because 22 isn't 8+13 



This same functionality could be gotten from a for() loop. The advantage of using every ( ) is the 
encapsulation of program logic in discrete functions that can be re-used in different places in your 
script. 

To equip browsers that don't yet support the every ( ) method of JavaScript 1.6, you can supply that 
functionality to the array object using code supplied by Mozilla.org: 

if (! Array . prototype . every ) 

{ 

Array . prototype . every = function(fun /*, thisp*/) 



332 



Chapter 18: The Array Object 



arrayObjecti i I ter () 

{ 

var 1 e n = this. length >>> 0; 
if (typeof fun != "function") 

{ 

throw new TypeErrorO; 

} 

var thisp = a rguments [ 1 ] ; 
for (var i = 0; i < len; i++) 
{ 

if (i in this && 

!fun. call (thisp, t h i s [ i ] , i , this)) 
return false; 

} 

return true; 

}; 

} 

Related Items: array, f i 1 ter ( ) , array. forEach( ) , array. map( ) methods 

array.fi Merical lback[ , thi sObject]) 

Returns: Array 

Compatibility: FF2+, Safari3+, Chromel+, Opera 9.5+, WmlE— , MacIE— 

Similar to every ( ), the f i 1 ter( ) method lets you test every element of an array with a 
callback function of your choice, and then returns a new array consisting of every element 
that tested true. The original array is not modified unless your callback function explicitly 
modifies it. 

The callback function examines a single array element and returns Boolean true or false. 

It takes three arguments: the value of the array element being examined, its index in the array, and a 

reference to the array object being traversed. Every element that tests true is added to the result array. 

This example uses our previous callback function to check for positive numbers: 

function i sPosi ti ve( i Val ue , ilndex, aArray) 
{ 

return ( i Value > 0); 

} 

var a = new Arrayd, -2, -3, 4, 5, -6); 
var a Re suit = a.filter(isPositive); 
// result: [1, 4, 5] 

Mozilla suggests the following code to compensate for browsers that don't yet support the 
f i 1 ter( ) method of JavaScript 1.6: 

if (! Array . prototype . fi 1 ter ) 
{ 

Array . prototype . fi 1 ter = function(fun /*, thisp*/) 

333 



Part III: JavaScript Core Language Reference 



arrayObject.iorEachQ 

{ 

var 1 e n = this. length >>> 0; 
if (typeof fun != "function") 
throw new TypeErrorO; 

var res = new Array ( ) ; 
var thisp = a rguments [ 1 ] ; 
for (var i = 0; i < len; i++) 

( 

if ( i in this) 
{ 

var val = t h i s [ i ] ; // in case fun mutates this 
if (fun. call (thisp, val, i, this)) 
res . push ( val ) ; 




return res; 

} ; 

} 

Related Items: a r ray . every () , a rray . f orEach ( ) , array. map(), array. some() 
methods 

array . f orEach ( ca 1 lback[, thi sObjectJ) 

Returns: Array 

Compatibility: FF2+, Safari3+, Chromel+, Opera 9.5+, WmlE— , MacIE— 

f o r E a c h ( ) executes a function on every element of an array. It does not return a value and the orig- 
inal array is not modified unless your callback function explicitly modifies it. 

The callback function takes three arguments: the value of the array element being examined, its index 
in the array, and a reference to the array object being traversed. 

The following example builds a message that displays the contents of an array. Note that in the call- 
back function bui 1 dMsg( ), the keyword this refers to the custom object oMsg that we're passing 
to forEach( ): 

function sendMessages ( sVal ue , ilndex, aArray) 
1 

sendMsg(sVal ue, this. text); // where sendMsgt) is defined elsewhere ... 

} 

var a = new Array( 'chris@example.com' , 'pat@example.net', 'jessie@example.org'); 

var oMessage = (text: "Dear friend, \nYou are cordially invited..."}; 
a. forEacht sendMessages, oMessage); 

Alternatively, the preceding example could be written using the more universally supported for( ) 
method: 

var a = new Array (' appl e ' , 'banana', 'cardamom', 'dandelion'); 
var oMsg = {buffer: 'This array contains:'!; 



334 



Chapter 18: The Array Object 



arrayOft/ecf.lastlndexOfO 

for (var i = 0; i < a. length; i++) 
{ 

oMsg. buffer += '\n' + i + ':' + a[i]; 

} 

al ert ( oMsg . buffer ) ; 

Mozilla suggests the following code to equip browsers that don't yet support the f o r E a c h ( ) method 
of JavaScript 1.6: 

if (! Array . prototype . forEach ) 
{ 

Array . prototype . forEach = function(fun /*, this p*/ ) 
{ 

var len = this. length >>> 0; 
if (typeof fun != "function") 
throw new TypeErrorO; 

var thisp = a rguments [ 1 ] ; 
for (var i = 0; i < len; i++) 
{ 

if ( i in this) 

fun. call (thisp, t h i s [ i ] , i , this); 

} 




Related Items: array, eve ry(), array, f i 1 ter ( ) , array.map(), array. some() methods 

array . i ndexOf (searchString[ , startFromJ) 
array . 1 astlndexOf ( searchString[ , sta rtFromJ) 

Returns: Index value of the array element whose value matches searchString, or — 1 if not found 
Compatibility: FF2+, Safari3+, Chromel+, Opera 9.5+, WinlE— , MacIE— 

These two methods search for an array element that matches searchString exactly and return the 
index of the first (or last) matching element, or return —1 if no match is found. 

The principle difference between these two methods is that i ndexOf ( ) searches from left to 
right, starting at the beginning of the array ascending and 1 astlndex0f( ) searches from right 
to left, from the end of the array descending. In either case, the value that's returned is the 
index of the found item — its offset from the beginning of the array. Therefore, if there's 
only one matching element in the array and startFrom is not specified, both i ndexOf ( ) 
and lastlndexOfO will return the same value because they'll find the same matching 
element. 

The optional startFrom argument tells the method how far from the beginning or end of the array 
to begin the search. If it's missing, it's assumed to be zero — that is, begin the search at the first (with 
indexOf ( )) or last (with 1 astlndexOf ( )) element. If startFrom is a positive number, it's used 
as a starting offset from the beginning of the array; if it's negative, it's used as an offset from the end 
of the array. 



335 



Part III: JavaScript Core Language Reference 



arrayObject. lastl ndexOf () 

Examples: 



var a = new Arrayt'cat', 'dog', 'cat'); 



// 


indexOf searches 


eft 


to r' 


ght : 












a . 


i ndexOf ( ' cat ' ) ; 




// 


resul t = 


0 


(search 


elements 0, 1, 


and 


2) 


a . 


i ndexOf ( ' cat ' , 1 ) ; 




// 


result = 


2 


(search 


elements 1 and 


2) 




a . 


indexOft 'cat' , 2) ; 




// 


result = 


2 


(search 


element 2) 






a . 


indexOf ( 'cat' , 3); 




// 


resul t = 


■1 


(no elements to search) 




a . 


indexOf ( 'cat' , -1) 




// 


resul t = 


2 


(search 


element 2) 






a . 


indexOft 'cat' , -2) 




// 


resul t = 


2 


(search 


elements 1 and 


2) 




a . 


indexOf( 'cat' , -3) 




// 


resul t = 


0 


(search 


elements 0, 1, 


and 


2) 


// 


lastlndexOf searches 


ri ght 


to left: 












a . 


1 astlndexOf ( ' cat ' ) 




// 


resul t = 


2 


(search 


elements 2, 1, 


a n d 


0) 


a . 


1 astlndexOf ( ' cat ' , 


1); 


// 


resul t = 


0 


(search 


elements 1 and 


0) 




a . 


1 astlndexOf ( ' cat ' , 


2); 


// 


resul t = 


2 


(search 


elements 2, 1, 


and 


0) 


a . 


1 astlndexOf ( ' cat ' , 


3) ; 


// 


resul t = 


2 


(search 


whole array) 






a . 


1 astlndexOf ( ' cat ' , 


-1) 


; // 


resul t = 


2 


(search 


elements 2, 1, 


and 


0) 


a . 


1 astlndexOf ( ' cat ' , 


-2) 


; // 


resul t = 


0 


(search 


elements 1 and 


0) 




a . 


1 astlndexOf ( ' cat ' , 


-3) 


; // 


resul t = 


0 


(search 


element 0) 







Mozilla suggests the following code to equip browsers that don't yet support the i ndexOf ( ) method 
of JavaScript 1.6: 

if (! Array . prototype . i ndexOf ) 

{ 

Array . prototype . i ndexOf = function(elt /*, from*/) 
{ 

var len = this. length >>> 0; 

var from = Number ( a rguments [ 1 ] ) || 0; 
from = (from < 0) 

? Math. ceil (from) 

: Math . f 1 oor ( f rom) ; 
if (from < 0) 
from += len; 

for (; from < len; from++) 

{ 

if (from in this && 

thi s[f rom] === elt) 
return from; 

} 

return -1; 




336 



Chapter 18: The Array Object 



arrayObject] o i n 

And the following to equip browsers that don't yet support I astlndex0f( ): 

if ('Array. prototype.lastlndexOf) 
{ 

Array . prototype . 1 astlndexOf = function(elt /*, from*/) 
{ 

var 1 er = thi s . 1 ength ; 

var from = Number ( a rgumerts [ 1 ]) ; 

if ( i sNaN ( f rom) ) 

{ 

from = 1 er - 1 ; 

} 

else 
{ 

from = (from < 0) 

? Math . cei 1 (from) 
: Math . f 1 oor ( f rom ) ; 
if (from < 0) 

from += 1 en ; 
else if (from >= 1 en ) 
from = 1 en - 1 ; 

} 



for ( ; from > -1 ; from- - ) 
{ 

if (from in this && 

thisffrom] === elt) 
return from; 

) 

return -1; 

) ; 

} 

array . joi n( sepa rat or St ring) 

Returns: String of entries from the array delimited by the separatorString value 

Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari+, Opera+, Chrome+ 

You cannot directly view data that is stored in an array. Nor can you put an array into a form element 
for transmittal to a server-side program that expects a string of text. To make the transition from dis- 
crete array elements to string, the a r r a y . j o i n ( ) method handles what would otherwise be a nasty 
string manipulation exercise. 

The sole parameter for this method is a string of one or more characters that you want to act as a 
delimiter between entries. For example, if you want commas between array items in their text version, 
the statement is 



var arrayText = myArray . j oi n ( " , " ) ; 



337 



Part III: JavaScript Core Language Reference 



arrayObject] o i n 



Invoking this method does not change the original array in any way. Therefore, you need to assign the 
results of this method to another variable or a value property of a form element. 



Example 

The script in Listing 18-6 converts an array of planet names into a text string. The page pro- 
vides you with a field to enter the delimiter string of your choice and shows the results in a 
text area. 



LISTING 18-6 



Using the Array . join () Method 

HTML: jsb-1806.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Array . joi n( )</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 18-06 . j s "></scri pt> 

</head> 

<body> 

<hl>Array . j oi n ( ) : Converting arrays to strings</hl> 
<f orm> 

<p>This document contains an array of planets in our solar system. </p> 
<P> 

< 1 a be 1 for="del imiter">Enter a string to act 

as a delimiter between entri es : </l abel > 
<input type="text" id="del imiter" name="delim" value="," size="5"> 

</p> 
<P> 

<input i d="di spl ayButton " type="button" val ue="Di spl ay as String") 
<input type="reset"> 

</p> 
<P> 

<textarea id="output" name="output" rows="4" cols="40" 
wrap="virtual "></textarea> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1806.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 



338 



Chapter 18: The Array Object 



arrayObjectmapO 



if ( document . getEl ementBy Id ) 
{ 

// point to critical elements 

oDelimiter = document . getEl ementBy Id (' del i mi ter ') ; 

oOutput = document . getEl ementBy Id( ' output ') ; 

var oButton = document . getEl ementBy Id (' di spl ayButton ') ; 

// if they al I exi st . . . 

if (oDelimiter && oOutput && oButton) 

{ 

// apply behavior to button 
oButton . oncl i ck = convert; 

// set global array 

solarSys = new Array ( "Mercury " , "Venus", "Earth", "Mars", "Jupiter" 
"Saturn", "Uranus", "Neptune"); 



// join array elements into a string 

function convert(evt) 

{ 

var delimiter = oDel imiter.val ue; 

oOutput . val ue = decodeURIComponent ( sol arSys . j oi n ( del i mi ter ) ) 



Notice that this method takes the parameter very literally. If you want to include non- 
alphanumeric characters, such as a newhne or tab, do so with URL-encoded characters (%0D 
for a carriage return; %09 for a tab) instead of inline string literals. Coming up in Listing 18-7, the 
results of the array. joinO method are subjected to the decodeURIComponent ( ) function in 
order to display them in the textarea. 

Related Items: s t r i n g . s p 1 i t ( ) method 

array. map( ca 1 lback[, thi sObject]) 

Returns: Array 

Compatibility: FF2+, Safari3+, Chromel+, Opera 9.5+, WmlE— , MacIE— 

map( ) creates a new array by running a user-provided function on each element of the original array. 

The callback function returns a value that is used to build the result array. It takes three arguments: 
the value of the array element being examined, its index in the array, and a reference to the array 
object being traversed. 

If provided, thisObject will be used as the this value within the callback function. 
Example: 

function square( i Val ue , ilndex, aArray) 
( 



339 



Part III: JavaScript Core Language Reference 



arrayObject.popO 

return i Value * i Value; 

} 

var a = new Array(0, 1, 2, 3, 4, 5, 6, 7); 
var b = a.map(square); 

// result: b == [0, 1, 4, 9, 16, 25, 36, 49] 
You could also write this by creating the callback function on-the-fly: 

var a = new Array(0, 1, 2, 3, 4, 5, 6, 7); 
var b = a . map ( f uncti on ( i ) { return i * i; }); 

Mozilla suggests the following code to equip browsers that don't yet support the map( ) method of 
JavaScript 1.6: 

if (! Array . prototype . map ) 

{ 

Array . prototype . map = function(fun /*, t hi s p * / ) 
{ 

var len = this. length >>> 0; 
if (typeof fun != "function") 
throw new fypeErrorO; 

var res = new Array(len); 
var thisp = a rguments [ 1 ] ; 
for (var i = 0; i < len; i++) 

{ 

if ( i in this) 

res[i] = fun. call (thisp, thisfi], i, this); 

1 

return res; 

} ; 

} 

Related Items: array.everyO, array. filterO, array. for Each () , array, some ( ) 
methods 

array. pop( ) 

array . push ( val ueOrObject) 
array . shi f t( ) 

array . unshi f t( val ueOrObject) 

Returns: One array entry value 

Compatibility: WinIE5.5+, MacIE— , NN4+, Moz+, Safari+, Opera+, Chrome+ 

The notion of a stack is well known to experienced programmers, especially those who know about 
the inner workings of assembly language at the CPU level. Even if you've never programmed a 
stack before, you have encountered the concept in real life many times. The classic analogy is the 
spring-loaded pile of cafeteria trays. If the pile were created one tray at a time, each tray would be 
pushed onto the top of the stack of trays. When a customer comes along, the topmost tray (the last 



340 



Chapter 18: The Array Object 



arrayOft/'ecf.reduceRightO 

one to be pushed onto the stack) gets popped off. The last one to be put on the stack is the first one 
to be taken off. 

JavaScript in modern browsers lets you turn an array into one of these spring-loaded stacks. But 
instead of placing trays on the pile, you can place any kind of data at either end of the stack, 
depending on which method you use to do the stacking. Similarly, you can extract an item from 
either end. 

Perhaps the most familiar terminology for this is push and pop. When you p u s h ( ) a value onto 
an array, the value is appended as the last entry in the array. When you issue the array. pop( ) 
method, the last item in the array is removed from the stack and is returned, and the array shrinks in 
length by one. In the following sequence of statements, watch what happens to the value of the array 
used as a stack: 

var source = new Array ( "Homer" , "Marge" , "Bart" ," Li sa" , "Maggi e" ) ; 
var stack = new ArrayO; 

// stack = <empty> 
stack. push(source[0]); 

// stack = "Homer" 
stack. push(source[2]); 

// stack = "Homer" , "Bart" 
var Simpsonl = stack. pop(); 

// stack = "Homer" ; Simpsonl = "Bart" 
var Simpson2 = stack. pop(); 

// stack = <empty> ; Simpson2 = "Homer" 

While push( ) and pop( ) work at the end of an array, another pair of methods works at the front. 
Their names are not as picturesque as p u s h ( ) and p o p ( ) . To insert a value at the front of an array, 
use the array. unshiftC) method; to grab the first element and remove it from the array, use 
a r ray . s h i f t ( ) . Of course, you are not required to use these methods in matching pairs. If you 
pus h ( ) a series of values onto the back end of an array, you can s hi ft ( ) them off from the front 
end without complaint. It all depends on how you need to process the data. 

Related Items: array . concat( ), array . si i ce( ) method 

array. reduce( ca 1 lback[ , initial Value]) 
array. reduceRi ght( ca 1 lback[ , initia 1 Value]) 

Returns: A single value 
Compatibility: FF3+, Safari4+ 

These methods reduce an array down to a single value, reduce ( ) operates on the array elements 
starting with the first element, whereas reduceRi ght( ) begins with the last element. Both methods 
accept as arguments a callback function and an optional initial value (since the very first iteration will 
have only one array element to work on). The callback function has two arguments, (f i rstVal ue, 
secondVal ue), which it processes in some way to derive a single return value. 

For example, the following code reduces an array of numbers down to their sum: 

function addEmUp(a, b) 
{ 

return a + b; 

} 



341 



Part III: JavaScript Core Language Reference 



arrayOft/'ecf.reduceRightO 

var a = new Arrayd, 2, 3, 4, 5); 
var b = a . reduce( addEmUp) ; 
// result: b == 15 

For simple addition, it doesn't matter whether the reduction occurred frontward or backward, but 
look at what happens when we apply that same callback to text. (Remember that in JavaScript the 
plus sign adds numbers but concatenates text.) 

var a = new Array (' d ' , ' e' , 's ' , 's ' , ' e ' , ' r ' , ' t ' , ' s ' ) ; 

var b = a . reduce(addEmUp) ; 
// result: b == 'desserts' 

var b = a . reduceRi ght ( addEmUp ) ; 
// result: b == 'stressed' 

Mozilla suggests the following code to equip browsers that don't yet support the reduce ( ) method 
of JavaScript 1.8: 

if (! Array . prototype . reduce ) 

{ 

Array . prototype . reduce = function(fun /*, initial*/) 
{ 

var len = this. length >>> 0; 
if (typeof fun != "function") 
throw new TypeErrorO; 

// no value to return if no initial value and an empty array 
if (len == 0 && a rguments . 1 ength == 1) 
throw new TypeErrorO; 

var i = 0 ; 

if ( a rguments . 1 ength >= 2) 
{ 

var rv = a rguments [ 1 ] ; 

1 

else 
( 

do 

{ 

if ( i in this) 
( 

rv = thi s[i++] ; 
break ; 

} 

// if array contains no values, no initial value to return 
if (++i >= len) 

throw new TypeErrorO; 

1 

while (true); 



342 



Chapter 18: The Array Object 



arrayOft/ecf.reduceRightO 

I 

for ( ; i < 1 en ; i++) 

{ 

if ( i in this) 

rv = fun. call (null, rv, this[i], i, this); 

} 

return rv; 

) ; 

} 

. . . and likewise for r e d u c e R i g h t ( ) : 

if ('Array. prototype.reduceRight) 
{ 

Array . prototype . reduceRi ght = function(fun /*, initial*/) 
{ 

var len = this. length >>> 0; 
if (typeof fun != "function") 
throw new TypeErrorO; 

// no value to return if no initial value, empty array 
if (len == 0 && a rguments . 1 ength == 1) 
throw new TypeErrorO; 

var i = len - 1; 

if ( a rguments . 1 ength >= 2) 

{ 

var rv = arguments [1] ; 

1 

else 
{ 

do 
{ 

if ( i in this) 
{ 

rv = this[i--]; 
break ; 

} 

// if array contains no values, no initial value to return 
if (--i < 0) 

throw new TypeErrorO; 

} 

while (true); 

1 

for ( ; i >= 0; i--) 
{ 

if ( i in this) 

343 



Part III: JavaScript Core Language Reference 



arrayObject. re verse () 

r v = fun. call (null, rv, this[i], i, this); 

} 

return rv; 

) ; 

} 

array. reverse( ) 

Returns: Array of entries in the opposite order of the original 

Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari+, Opera+, Chrome+ 

Occasionally, you may find it more convenient to work with an array of data in reverse order. 
Although you can concoct repeat loops to count backward through index values, a server-side 
program may prefer the data in a sequence opposite to the way it was most convenient for you to 
script it. 

You can have JavaScript switch the contents of an array for you: Whatever element was last 
in the array becomes the 0 index item in the array. Bear in mind that if you do this, you're 
restructuring the original array, not copying it, even though the method also returns a copy of 
the reversed version. A reload of the document restores the order as written in the HTML document. 



Example 

Listing 18-7 is an enhanced version of Listing 18-6, which includes another button and function that 
reverse the array and display it as a string in a text area. 



LISTING 18-7 



Array. reverseO Method 

HTML: jsb-1807.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Array.reverse( )</title> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 18-07 . j s "></scri pt> 

</head> 

<body> 

<hl>Array . reverse( ) : Reversing array element order</hl> 
<f orm> 

<p>This document contains an array of planets in our solar system. </p> 
<P> 

< 1 a be 1 for="del imiter">Enter a string to act as 

a delimiter between entri es : </l abel > 
<input type="text" id="del imiter" name="delim" value="," size="5"> 

</p> 
<P> 

<input type="button" id="showAs!s" value="Array as-is"> 



344 



Chapter 18: The Array Object 



arrayObject.re\erse() 

<input type="button" id="reverselt" val ue="Reverse the array"> 
<input type="reset"> 

<input type="button" id="rel oad" val ue="Rel oad"> 

</p> 
<P> 

<textarea id="output" name="output" rows="4" cols="40" 
wrap="virtual "></textarea> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-1807.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld) 

{ 

// point to critical elements 

oDelimiter = document . getEl ementByld (' del i mi ter ') ; 
oOutput = document . getEl ementById( ' output ') ; 
var oButtonShowAs I s = document . getEl ementById( ' showAs I s ') ; 
var oButtonReverselt = document . getEl ementById( ' reverselt ') ; 
var oReload = document . getEl ementById( ' rel oad ') ; 

// if they al I exi st . . . 

if (oDelimiter && oOutput && oButtonShowAs I s && oButtonReverselt) 
{ 

// apply behaviors to buttons 

oButtonShowAs I s . oncl i ck = showAsIs; 

oButtonReverselt . oncl i ck = reverselt; 

oRel oad . oncl i ck = functionO ( I ocati on . rel oad( ) ; ); 

// set global array 

solarSys = new Array ( "Mercury" , "Venus", "Earth", "Mars", "Jupiter", 
"Saturn", "Uranus", "Neptune"); 

I 

) 

} 

// show array as currently in memory 

function showAs I s ( evt ) 

{ 

var delimiter = oDel i mi ter . val ue ; 

oOutput . val ue = decodeURIComponent ( sol arSys . j oi n ( del i mi ter ) ) ; 

} 

// reverse array order, then display as string 

continued 



345 



Part III: JavaScript Core Language Reference 



arrayObject.sMceQ 



LISTING 18-7 



(continued) 



function reverselt(evt) 



var delimiter = oDel i mi ter . val ue ; 

sol arSys . reverse( ) ; // reverses original array 

oOutput . val ue = decodeURIComponent ( sol arSys . j oi n ( del i mi ter ) 



Notice that the solarSys.reverseO method stands by itself (meaning, nothing captures the 
returned value) because the method modifies the sol arSys array. You then run the now-inverted 
s o 1 a r S y s array through the a r r a y . j o i n ( ) method for your text display. 

Related Items: array. sort( ) method 

array . si i ce( startlndex [, endlndex~\) 

Returns: Array 

Compatibility: WinIE4+, MacIE4+, NN44-, Moz4-, Safari 4-, Opera 4-, Chrome4- 

Behaving as its like-named string method, array, si ice() lets you extract a contiguous series of 
items from an array. The extracted segment becomes an entirely new array object. Values and objects 
from the original array have the same kind of behavior as arrays created with the array. concatO 
method. 

One parameter is required — the starting index point for the extraction. If you don't specify a second 
parameter, the extraction goes all the way to the end of the array; otherwise the extraction goes to, 
but does not include, the index value supplied as the second parameter. For example, extracting Earth's 
neighbors from an array of planet names looks like the following: 

var solarSys = new Array( "Mercury" , "Venus" , "Earth" , "Mars" , 

" J u p i t e r " , " S a t u r n " , " U r a n u s " , " N e p t u n e " , " P 1 u t o " ) ; 
var nearby = solarSys. si iced, 4); 

// result: new array of "Venus", "Earth", "Mars" 

Related Items: array, spl ice( ), string, si ice( ) methods 

array .sort ([compare Function] ) 

Returns: Array of entries in the order as determined by the compareFunction algorithm 

Compatibility: WinIE44-, MacIE44-, NN34-, Moz-E, Safari 4-, Opera4-, Chrome4- 

JavaScript array sorting is both powerful and a bit complex to script if you haven't had expe- 
rience with this kind of sorting methodology. The purpose, obviously, is to let your scripts 
sort entries of an array by almost any kind of criterion that you can associate with an entry. For 
entries consisting of strings, the criterion may be their alphabetical order or their length; for numeric 
entries, the criterion may be their numerical order. 

Look first at the kind of sorting you can do with the array. sort() method by itself (for example, 
without calling a comparison function). When no parameter is specified, JavaScript takes a snapshot of 



346 



Chapter 18: The Array Object 



arrayObject.sort() 

the contents of the array and converts items to strings. From there, it performs a string sort of the val- 
ues. ASCII values of characters govern the sort, which means that numbers are sorted by their string 
values, not their numeric values. This fact has strong implications if your array consists of numeric 
data: The value 201 sorts before 88, because the sorting mechanism compares the first characters of 
the strings ("2" versus "8") to determine the sort order. For simple alphabetical sorting of string values 
in arrays, the plain array. sort( ) method does the trick. 

Fortunately, additional intelligence is available that you can add to array sorting. The key tactic is to 
define a function that helps the sort ( ) method compare items in the array. A comparison function 
is passed two values from the array (what you don't see is that the array. sort( ) method rapidly 
sends numerous pairs of values from the array to help it sort through all entries). The comparison 
function lets the s o r t ( ) method know which of the two items comes before the other, based on the 
value the function returns. Assuming that the function compares two values, a and b, the returned 
value reveals information to the sort( ) method, as shown in Table 18-1. 



TABLE 18-1 



Comparison Function Return Values 


Return Value Range 


Meaning 


< 0 


Value b should sort later than a. 


0 


The order of a and b should not change. 


> 0 


Value a should sort later than b. 



Consider the following example: 

myArray = new Array(12, 5, 200, 80); 

function compare(a,b) 

{ 

return a - b; 

} 

myArray. sort(compare) ; 

The array has four numeric values in it. To sort the items in numerical order, you define a compar- 
ison function (arbitrarily named compare( )), which is called from the sort( ) method. Note that 
unlike invoking other functions, the parameter of the sort( ) method uses a reference to the func- 
tion, which lacks parentheses. 

When the compare( ) function is called, JavaScript automatically sends two parameters to the func- 
tion in rapid succession until each element has been compared with the others. Every time com- 
pare( ) is called, JavaScript assigns two of the array's values to the parameter variables (a and b). 
In the preceding example, the returned value is the difference between a and b. If a is larger than b, 
then a positive value goes back to the sort( ) method, telling it to sort a later than b (that is, posi- 
tion a at a higher value index position than b). Therefore, b may end up at myArray [0], whereas 
a ends up at a higher index-valued location. On the other hand, if a is smaller than b, the returned 
negative value tells sort( ) to put a in a lower index value spot than b. 

Evaluations within the comparison function can go to great lengths, as long as some data connected 
with array values can be compared. For example, instead of numerical comparisons, as just shown, 



347 



Part III: JavaScript Core Language Reference 



arrayObject.so rt () 

you can perform string comparisons. The following function sorts alphabetically by the last character 
of each array string entry: 

function compare(a.b) 

{ 

// last character of array strings 
var aComp = a . cha rAt ( a . 1 ength - 1); 
var bComp = b . cha rAt ( b . 1 ength - 1); 
if (aComp < bComp) 

return -1; 
if (aComp > bComp) 

return 1; 
return 0; 

} 

First, this function extracts the final character from each of the two values passed to it. Then, because 
strings cannot be added or subtracted like numbers, you compare the ASCII values of the two char- 
acters, returning the corresponding values to the sort ( ) method to let it know how to treat the two 
values being checked at that instant. 

When an array's entries happen to be objects, you can even sort by properties of those objects. 
If you bear in mind that the a and b parameters of the sort function are references to two 
array entries, then by extension you can refer to properties of those objects. For example, if 
an array contains objects whose properties define information about employees, one of the properties 
of those objects can be the employee's age as a string. You can then sort the array based on the 
numeric equivalent of the age property of the objects by way of the following comparison function: 

function compare(a.b) { 

return parselnt(a . age) - pa rsel nt ( b . age ) ; 

} 

Array sorting, unlike sorting routines you may find in other scripting languages, is not a stable sort. 
Not being stable means that succeeding sort routines on the same array are not cumulative. Also, 
remember that sorting changes the sort order of the original array. If you don't want the original array 
harmed, make a copy of it before sorting or reload the document to restore an array to its original 
order. Should an array element be null, the method sorts such elements at the end of the sorted 
array. 

JavaScript array sorting is extremely powerful stuff. Array sorting is one reason why it's not uncom- 
mon to take the time during the loading of a page containing an IE XML data island, for example, to 
make a JavaScript copy of the data as an array of objects (see Chapter 60, "Application: Transforming 
XML Data," on the CD-ROM). Converting the XML to JavaScript arrays makes the job of sorting the 
data much easier and faster than cobbling together your own sorting routines on the XML elements. 

Example 

You can look to Listing 18-8 for a few examples of sorting an array of string values (see Figure 18-2). 
Four buttons summon different sorting routines, three of which invoke comparison functions. This 
listing sorts the planet array alphabetically (forward and backward) by the last character of the planet 
name and also by the length of the planet name. Each comparison function demonstrates different 
ways of comparing data sent during a sort. 



348 



Chapter 18: The Array Object 



arrayObject.sortQ 



FIGURE 18-2 



Sorting an array of planet names alphabetically by name length. 



'■' Array.sortO - Mozllla Flrefox 



JEW 



Be Ettt Wew History Bookmarks loots Help 



Array .M>rlO 



Arrfly.sort(): Sorting array elements 

iTiis donrmen] «ntams an array of planets in out solar s;, stem 
AlphafaebMlA-Z | J^ahabetksJZ-A | LailCMiacLe- - | Name -ervjUi | Re-bad 
rifl - ? : '.---.i; ? r r. a tt h r 3d turn : i/raru 3 rYerrjr >■; -"up s.t« rj-JfeptMe 



Dons 



LISTING 18-8 



Array.sortO Possibilities 

HTML: jsb-18-08.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<titl e>Array. sort ( )</ tit! e> 

<script type=" text /javascript" src=". ./jsb-global .js"X/script> 
<script type="text/ j avascri pt" src="j sb- 18-08 . j s "></scri pt> 

</head> 

<body> 

<hl>Array . sort ( ) : Sorting array el ements</hl> 
<f orm> 

<p>This document contains an array of planets in our solar system. </p> 

<P> 

<input type="button" id="sortAsc" val ue="Al phabeti cal A-Z"> 
<input type="button" i d="sortDesc" val ue="Al phabeti cal Z-A"> 

continued 



349 



Part III: JavaScript Core Language Reference 



arrayObject.so rt () 



LISTING 18-8 



(continued) 



<input type="button" i d="sortl_astChar" value="Last Character") 
<input type="button" id="sortLength" value="Name Length") 
<input type="button" id="rel oad" val ue="Rel oad"> 

</p> 
<P> 

<textarea id="output" name="output" rows="3" cols="60" 
wrap="virtual "></textarea> 

</p> 
</ f orm> 
</body> 
</html > 



JavaScript: jsb-1808.js 



// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// do this only if the browser can handle DOM methods 

if ( document . getEl ementByld ) 

{ 

// point to critical elements 

oOutput = document . getEl ementById( ' output ') ; 

var oESuttonSortAsc = document . getEl ementByld (' sortAsc ') ; 

var oButtonSortDesc = document . getEl ementByld (' sortDesc ') ; 

var oButtonSortLastChar = document . getEl ementById( ' sortLastChar ') ; 

var oButtonSortLength = document . getEl ementById( ' sortLength ') ; 

var oReload = document . getEl ementById( ' rel oad ') ; 

// if they al 1 exi st . . . 

if (oOutput && oButtonSortAsc && oButtonSortDesc && oButtonSortLastChar 
&& oButtonSortLength && oReload) 

{ 

// apply behaviors to buttons 

oButtonSortAsc . oncl i ck = functionO ( sortlt(null) ); 
oButtonSortDesc . oncl i ck = functionO { sortIt( comparel ) ); 
oButtonSortLastChar . oncl i ck = functionO { sortIt(compare2) ); 
oButtonSortLength . oncl i ck = functionO ( sortIt(compare3) ); 
oRel oad . oncl i ck = functionO ( 1 ocati on . rel oad( ) ; ); 

// set global array 

solarSys = new Array ( "Mercury" , "Venus", "Earth", "Mars", "Jupiter", 
"Saturn", "Uranus", "Neptune"); 



350 



Chapter 18: The Array Object 



arrayObject.sort() 

II comparison functions 
function comparel ( a , b ) 
{ 

// reverse alphabetical order 
if (a > b) 

return -1; 
if (b > a) 

return 1; 
return 0; 

} 

function compare2 ( a , b ) 
{ 

// last character of planet names 
var aComp = a . charAt ( a . 1 ength - 1); 
var bComp = b . charAt ( b . 1 ength - 1); 
if (aComp < bComp) 

return -1; 
if (aComp > bComp) 

return 1; 
return 0; 



function compare3 ( a , b ) 
{ 

// length of planet names 
return a. length - b. length; 

} 

// sort and display array 
function sortlt(compFunc) 
{ 

i f ( compFunc == null) 
{ 

sol arSys . sort( ) ; 

} 

el se 
{ 

solar Sys.sort(compFunc); 

} 

// display results in field 
var del imiter = " ; " ; 

oOutput . val ue = decodeURIComponent ( sol arSys . j oi n ( del i mi ter ) ) ; 



Related Items: a rray . reverse ( ) method 



351 



Part III: JavaScript Core Language Reference 



arrayObject.spWceO 

Note 

As we show you in Chapter 45, many regular expression object methods generate arrays as their result (for 
example, an array of matching values in a string). These special arrays have a custom set of named proper- 
ties that assist your script in analyzing the findings of the method. Beyond that, these regular expression result 
arrays behave like all others. ■ 

array .spMceistartlndex , del eteCountl , itemll, 
itemZl /tem/V]]]) 

Returns: Array 

Compatibility: WmIE5.5+, MacIE-, NN4+, Moz+, Safari+, Opera+, Chrome+ 

If you need to remove items from the middle of an array, the array. splice() method simplifies 
a task that would otherwise require assembling a new array from selected items of the original array. 
The first of two required parameters is a zero-based index integer that points to the first item to be 
removed from the current array. The second parameter is another integer that indicates how many 
sequential items are to be removed from the array. Removing array items affects the length of the 
array, and those items that are removed are returned by the spl i ce ( ) method as their own array. 

You can also use the spl i ce( ) method to replace array items. Optional parameters beginning with 
the third let you provide data elements that are to be inserted into the array in place of the items 
being removed. Each added item can be any JavaScript data type, and the number of new items does 
not have to be equal to the number of items removed. In fact, by specifying a second parameter of 
zero, you can use spl i ce ( ) to insert one or more items into any position of the array. 

Example 

Use The Evaluator (see Chapter 4) to experiment with the spl i ce( ) method. Begin by creating an 
array with a sequence of numbers: 

a = new Array (1,2,3,4,5) 

Next, remove the center three items, and replace them with one string item: 

a. spliced, 3, "two/three/four") 

The Results box shows a string version of the three-item array returned by the method. To view the 
current contents of the array, enter a into the top text box. 

To put the original numbers back into the array, swap the string item with three numeric items: 

a. spliced, 1, 2, 3, 4) 
The method returns the single string, and the a array now has five items in it again. 
Related Item: array. si ice( ) method 

array. toLocal eStri ng( ) 

Returns: String 

Compatibility: WmIE5.54-, MacIE-, NN64-, Moz4-, Safari-!-, Opera4-, Chrome4- 

352 



Chapter 18: The Array Object 



arrayObject. toStringO 

array. toStringC ) 

Returns: String 

Compatibility: WinIE4+, MacIE4+, NN3+, Moz+, Safari+, Opera+, Chrome + 

The array. toLocaleString( ) and the older, more compatible array. toSt ri ng ( ) are meth- 
ods to retrieve the contents of an array in string form. Browsers use the toStri ng ( ) method on 
their own whenever you attempt to display an array in text boxes, in which case the array items are 
comma-delimited. 

The precise string conversion of the toLocaleString() is left up to the specific browser 
implementation. That browsers differ in some details is not surprising, even in the U.S. English 
versions of operating systems and browsers. For example, if the array contains integer values, the 
toLocal eStri ng( ) method in IE5.5+ returns the numbers comma-and-space-delimited, formatted 
with two digits to the right of the decimal (as if dollars and cents). Mozilla-based browsers, on the 
other hand, return just the integers, but these are also comma-delimited. 

If you need to convert an array to a string for purposes of passing array data to other venues (for 
example, as data in a hidden text box submitted to a server or as search string data conveyed to 
another page), use the array. join( ) method instead. Array. jo in( ) gives you more reliable 
and flexible control over the item delimiters, and you are assured of the same results regardless of 
locale. 

Related Item: a r r a y . j o i n ( ) method 



Array Comprehensions 

Compatibility: FF2+ 

A feature of JavaScript 1.7 is an enhancement to JavaScript syntax called array comprehensions, a short- 
cut for building a new array based on another. Comprehensions can often replace the map( ) and 
f i 1 ter() methods. 

Here's an example that uses a comprehension to produce a modified version of every element in an 
array: 

var alntegers = new Array(0, 1, 2, 3, 4, 5, 6, 7); 
var aResults = [i * i for each (i in alntegers)]; 

// result: aResults == [0, 1, 4, 9, 16, 25, 36, 49] 

This is the equivalent of the map( ) syntax: 

function square(i Value) 
{ 

return i Value * i Value; 

} 

var alntegers = new Array(0, 1, 2, 3, 4, 5, 6, 7); 
var aResults = a I ntegers . map ( squa re ) ; 



353 



Part III: JavaScript Core Language Reference 



Array comprehensions can also be used to select certain elements from an array: 

var aNumbers = new Array(l, -2, -3, 4, 5, -6); 

var aResult = [i for each (i in aNumbers) if (i > 0)]; 

// result: aResult == [1, 4, 5] 
This is the equivalent of the f i 1 1 e r ( ) syntax: 

function i s Pos i ti ve ( i Va 1 ue , ilndex, aArray) 

{ 

return (i Value > 0); 

} 

var aNumbers = new Arrayd, -2, -3, 4, 5, -6); 
var aResult = aNumbers . fi 1 ter ( i s Pos i ti ve ) ; 

The square brackets of an array comprehension introduce an implicit block for scoping purposes. 
New variables (such as i in the preceding examples) have local scope (are treated as if they had been 
declared using 1 et) and are not available outside of the comprehension. 

The input to an array comprehension does not itself need to be an array; iterators and generators can 
also be used (see Chapter 21). 



Destructuring Assignment 

Compatibility: FF2+, Opera 9.5 (partial) 

Destructuring assignment (introduced with JavaScript 1.7 and corrected in 1.8) makes it easy to 
extract an array from another array, object, or function. You can view it as setting one array equal to 
another: 

[a, b, c] = [1, 2, 3] 

// result: a == 1, b == 2, and c == 3 

This syntax provides a succinct way to swap the values of variables: 

var x = 1 ; 
var y = 2 ; 

[x, y] = [y, x] 

// result: x == 2 and y == 1 

. . . replacing the more conventional technique that employs a third temporary variable to swap two 
values: 

temp = x; 
x = y; 
y = temp; 

Another example is receiving an array of values from a function: 



354 



Chapter 18: The Array Object 



function f u n ( ) 
{ 

return [3, 'aardvark', 0]; 

} 

[a, b, c] = fun() 

// result: a == 3 , b == 'aardvark', and c == 0 

As of this writing, destructuring assignment is supported by Firefox 2.0+ and partially by 
Opera 9.5 but not at all by Internet Explorer 8 and other browsers. We can't use JavaScript to 
test a browser's ability to execute this code because an older version will simply crash trying 
to compile it. We can "firewall" this code with a special script tag: 

<scri pt type="appl i cati on/ javascri pt ; versi on=l . 8" src="scri ptname . j s "></scri pt> 

However, we question the usefulness of this if we also have to provide more conventional syntax for 
other browsers. Unless we're in a special circumstance in which we can guarantee that our code will 
be running in a browser that incorporates JavaScript 1.8, we may just have to wait until destructuring 
assignment syntax is more universally adopted by the other browser manufacturers. 



Compatibility with Older Browsers 

Some of the features described in this chapter were introduced with JavaScript 1.6 and later. 
They run in Firefox 2.0+ or 3.0+ and occasional others but are not supported in many other 
browsers, including Internet Explorer 8. New array object methods such as every( ) and 
f i 1 ter( ) can be used in our cross-browser scripts simply by adding them to the object prototype 
when they're not already there, as we've listed in this chapter. However, innovations of syntax, 
including array comprehensions and destructuring assignment, cannot be included in blocks of script 
run by legacy browsers because older versions of JavaScript will simply stop cold during the compile 
phase and will not run any of the script on the page. 

Should we then refrain from using the new syntax until it's universally supported? 

As mentioned in Chapter 4, there is a way to identify a block of code so that it will run only in a 
given version of JavaScript or greater — for example: 

<script type=" text/ javascript" src=" for -every one. js'X/scri pt> 

<script type="appl i cat ion/ javascri pt; versi on=l. 7" src="new-stuff . js"X/script> 

You can isolate sections of code in this way to execute only if the browser is capable, separated safely 
from older user agents. 

The question then comes, what alternative code will you run if the browser is older? If you have to 
write code that performs the same operation as an array comprehension to support older browsers, 
why not simply use that code for all browsers? 

As with any facet of web development, and JavaScript in particular, make sure that all basic function- 
ality on a page is intact even in the absence of JavaScript or any specific features of the language; then 
add enhancements when scripting and any of its advanced features are available. This principle of pro- 
gressive enhancement ensures that while your pages may work better or faster for those with fancier 
tools, they will work fundamentally for everyone. 



355 



CHAPTLR 



JSON — Native 
JavaScript Object 
Notation 




JSON (JavaScript Object Notation) is a lightweight way to represent data 
structures that many programming languages can easily read and write. This 
makes it (similarly to XML) a useful data interchange format among applica- 
tions written in a variety of languages, for example, between server-side PHP 
and client-side JavaScript. With the ECMAScript Fifth Edition standard, JSON is 
now formally part of the language and will be increasingly supported by more 
browsers over the coming years. In the meantime, there is freely available code 
to assist older browsers. 

JSON was developed by Douglas Crockford and presented to the Internet 
community in 2006. It was formally made part of the ECMAScript standard, on 
which JavaScript is based, as of the Fifth Edition finalized in April 2010. 



IN THIS CHAPTER 



How JSON works 

Sending and receiving JSON 
data 

JSON object methods 
Security concerns 



How JSON Works 

JSON combines two aspects of JavaScript syntax for representing arrays and 
objects to present data structures — simple array notation using brackets [ ] : 

[ "iteml", "item2", "item3" ] 
and the notation for objects and associative arrays using curly braces { ) : 

{ "key": "value" ) 

We have access to the embedded values by numerical index in the first case 
(remember that the first item has an index of zero): 



var altems = [ "iteml", "item2", "item3" ]; 
// e.g., altems[0] == "iteml" 

and by key name in the second: 

var oExample = ( "charlie": "horse" }; 
// oExampl e [ " cha rl i e" ] == "horse" 
// oExampl e . cha rl i e == "horse" 



357 



Part III: JavaScript Core Language Reference 



Using these two conventions, one can describe many data structures with sub-records having either 
named or numerically indexed keys: 

var oNovelist = 

{ 

"fi rstName" : "Joanna" , 
"1 astName" : "Russ" , 
"novels": 
[ 

{ 

"title": "And Choas Died", 
"year": "1970" 



"title": "The Female Man", 
"year": "1975" 



In this example, f i rstName and 1 astName have simple string values, while novel s is a numeri- 
cally indexed array. Here are two ways to refer to these values: 

var sMsg = oNovel i st[ ' fi rstName ' ] + ' ' + oNovel i st[ ' 1 astName ' ] + "'s novel " + 
oNovel i st [' novel s '] [0] [' ti tl e ' ] + ' was published in ' + 
oNovel i st[ ' novel s '] [0] [ 'year ' ] + '.'; 

var sMsg = oNovel i st . fi rstName + ' ' + oNovel i st . 1 astName + "'s novel " + 
oNovel i st . novel s [0] . ti tl e + ' was published in ' + 
oNovel i st . novel s [0] .year + 

// result: Joanna Russ's novel And Chaos Died was published in 1970. 

In the first example, we're treating the structure as an associative array with bracketed keys. In the 
second, we're using dot-notation to retrieve the object's properties. The first syntax will always work 
because the keys, when strings, are quoted. We got away with using dot-notation in the second 
example because none of these keys contained characters such as hyphens, periods, and other 
characters that are legal key values but would throw JavaScript a curve: 

var sMsg = oNovel i st[ ' fi rst-name '] ; // this works 

var sMsg = oNovel i st.fi rst-name; // oh no! JavaScript tries to subtract 

Cross-Reference 

For more on this point, see the section "Simulating a Hash Table" in Chapter 18, "The Array Object." ■ 

Data types 

Six types of data can occur as a JSON value: 

• String (a collection of zero or more Unicode characters, wrapped in double quotes, using 
backslash escapes) 

• Number (integer or real; no octal and hexadecimal formats) 



358 



Chapter 19: JSON — Native JavaScript Object Notation 



• Object (a collection of key:value pairs, comma-separated and enclosed in curly braces) 

• Array (an ordered sequence of values, comma-separated and enclosed in square brackets) 

• Boolean (true or fal se) 

• null 

Whitespace can be inserted between any pair of tokens. 



Sending and Receiving JSON Data 

Because JSON grammar uses JavaScript's normal object and array syntax, we don't need any add-ons 
to the language in order to be able to build and read JSON data structures within a single script. It's 
when we need to share these structures between scripts that complications arise. 

In order to read, write, send, and receive a JSON data object, we need to convert it to and from 
a string. The standard way of doing this is to read and write exactly the same syntax we'd use in 
JavaScript: 

I "f i rstName" : "Joanna " , "l astName" : " Russ" , "novel s " : [ I "ti tl e" : "And Choas 
Died" , "year" : " 1970" 1 , ! " t i 1 1 e " : "The Femal e Man" , "year" : " 1975" I ] ) 

This string can then be imported into any of the programming languages that work with JSON. 

Performing this conversion between object and string in JavaScript is simple enough. There are func- 
tions at http://json.org that we're encouraged to use for older browsers so that we don't have to 
reinvent the wheel. 

Because the JSON data is stored in a string exactly as it is in JavaScript source code, on first glance it 
might seem that the most expedient way to convert it from a string back to an object is by using the 
JavaScript method e v a 1 ( ) : 

var sStringJSON = readJSONDataFromWhateverSource( ) ; 

evalC'var oJSON = " + sStri ngJSON ) ; 
// or : 

var oJSON = evaK'C + sStringJSON + ')'); 

Now oJS0N.fi rstName will yield Joanna' for the example above. (In the second use of eval ( ), 
note the necessary inclusion of parentheses around the JSON string to satisfy the JavaScript 
interpreter.) 

However, we can't over-emphasize that eval ( ) opens up a doorway for malicious exploits in 
JavaScript and should be avoided on any public page. A proper JSON parser will walk through the 
data string character by character to build the JSON object rather than yielding to the temptation to 
use eval ( ). 

JSON goes native 

The JSON object was made part of the language with the ECMAScript Fifth Edition standard, pub- 
lished in December 2009. Mozilla implemented this in JavaScript 1.8.1, in the Gecko layout engine 
version 1.9.1 that drives Firefox 3.5, Thunderbird 3, and SeaMonkey 2. Other browser development 
teams are sure to follow their lead. 



359 



Part III: JavaScript Core Language Reference 



JSONObject 

The JSON object has two methods, parse( ) and stringify( ). The toJS0N( ) method is also 
added to the Date object. 

JSON Object 

Properties Methods 

parse( ) 

s t r i n g i f y ( ) 



Methods 

JSON . parse( string [, transl ator]) 

Returns: JSON object reference 
Compatibility: Mozl.9.1+, Firefox3.5+ 

Use the JSON. parseO method to convert a JSON string to a JSON object. 

object - JSON . parse( string, transl ator) 
The string parameter is the "stringified" JSON to be converted to an object. 
Related Item: J SO N . s t r i n g i f y ( ) method 

JSON . stri ngi fy( object [, replacer [, space]]) 

Returns: JSON string 

Compatibility: Mozl.9.1+, Firefox3.5+ 

JSON . stri ngi fy ( ) converts a JSON object to a JSON string. 

string = JSON . stri ngi fy ( object , replacer, space) 
The object parameter is the JSON object to be converted to a string. 

repl acer is an optional parameter that is either a function that alters the behavior of the stringi- 
fication process or an array of String and Number objects that serve as a whitelist for selecting the 
properties of the object to be stringified. If this value is null or not provided, all properties of the 
object are included in the resulting JSON string. 

space is a String or Number object that's used to insert white space into the output JSON string for 
readability purposes. If this is a Number, it indicates the number of space characters to use as white 
space; this number is capped at 10 if it's larger than that. Values less than 1 indicate that no space 
should be used. If this is a String, the string (or the first 10 characters of the string, if it's longer than 
that) is used as white space. If this parameter is not provided (or is null), no white space is used. 

Related Item: JSON.parseO method 



360 



Chapter 19: JSON — Native JavaScript Object Notation 



Security Concerns 

Some concern has been expressed about the vulnerability JSON presents in web security. We feel that 
these issues can be dismissed with sufficiently careful use of the technology. 

Using eval ( ) to convert a JSON string to an object (or for any other purpose on a public page) is 
an easy pitfall to avoid. If a method (function) is embedded in serialized JSON and eval ( ) is used 
to convert it, JavaScript code can be executed without the permission of the page author's script. 
The obvious solution is to use a non-eval ( ) parsing algorithm, such as that published by Douglas 
Crockford, on older browsers and the new JSON object method parse( ) on newer browsers. 

The DOM method XM LHttpReques t ( ) is commonly used to exchange information between server 
and client. By default it permits exchanges only with the server from which the current page has orig- 
inated. However, by injecting a scri pt tag that links to an off-site JavaScript file, this protection can 
be circumvented. The solution here is to be vigilant when it comes to allowing JavaScript from third 
parties to execute on your page. 



361 



CHAPTLR 



E4X — Native XML 
Processing 




With the rise in popularity of Ajax (Asynchronous JavaScript and XML) 
connectivity in recent years, it's become commonplace for web devel- 
opers who might otherwise never stray beyond the bounds of HTML 
to work with XML (Extensible Markup Language). In fact, XML has been consid- 
ered so fundamental to everyday web development that the ECMA has incorpo- 
rated it into the very syntactical fabric of JavaScript. We can now write unquoted 
XML markup right into our JavaScript statements — as permitted by the most 
recent browsers. 

This new feature of JavaScript syntax places XML uniquely on both sides of a 
major divide. Every other aspect of scripting is either part of the core JavaScript 
language or part of the DOM (Document Object Model). XML is now a member 
of both camps. 

We discuss techniques for transmitting XML between client and server in 
Chapter 39, "Ajax, E4X, and XML" (on the CD). 



IN THIS CHAPTER 



Using the XML object 

Adding elements and 
attributes 

Selecting records 

Serializing XML objects to text 



XML 



Briefly, XML is a markup language designed to contain and transmit textual data. 
It consists of nested elements marked up with three types of tag — matching 
begin- and end-tags 

<hobby>music</hobby> 
and empty-element tags 

<breathe/> 

Elements can contain attributes, which are name/value pairs that reside within 
the opening or empty tag: 



<fax 1 ocation="home" call -fi rst="true">123-456-7890</f ax> : 



363 



Part III: JavaScript Core Language Reference 



XMLObject 

Unlike HTML and XHTML, in which element and attribute name choices are constrained by the 
Document Type Declaration or XMLSchema, XML element and attribute names are completely 
arbitrary and defined by the author of the data to suit the current purpose. 

For a complete formal description of XML, see the W3C specification at http : / /w3 . org/TR/ 
REC-xml /. 

ECMAScript for XML (E4X) 

Prior to E4X, the only way to access XML documents with JavaScript was through the DOM at the 
object level. With the advent of E4X, XML is treated as a primitive, at the same level as strings, num- 
bers, and Booleans. What does this mean to us? The short story is that XML access is now simpler for 
us as web developers, and faster for the end user. An XML object created with the XML primitive is 
not part of the DOM; neither is it a DOM representation of XML. Because it is a primitive, you use it 
in ways similar to how you use other JavaScript objects. 

Using the XML object 

With E4X you declare an XML object, in much the same way that you declare a string or numeric or 
Boolean object, with the XML constructor: 

var oCopyright = new XML(); 
You can initialize the object using text: 

var sXMLText = "<copyri ght>" 

+ "<date>2010</date>" 

+ "<author>Danny Goodman</author>" 

+ "</copyri ght>" ; 

var oCopyright = new XML( sXMLText ) ; 

Remarkably, you can also use unquoted XML markup in an assignment statement, which implicitly 
creates the XML object: 

var oCopyright = <copyright> 

<date>2010</date> 
<author>Danny Goodman</author> 
</copyright>; 

This type of syntax, in which specially constructed text can be assigned without quotation marks, 
may be reminiscent of JavaScript's native regular expression syntax, as described in Chapter 45, "The 
Regular Expression and RegExp Objects." 

XML elements 

The XML elements within the XML object are its properties. You can use both the familiar 
object. property dot-notation and the object [property] bracket-notation to reference 
elements and their values: 

var sText = "Copyright " + oCopyri ght . date + " by " + oCopyri ght . author ; 

var sText = "Copyright " + oCopyri ght[ ' date ' ] + " by " + oCopyri ght[ ' author '] ; 



364 



Chapter 20: E4X — Native XML Processing 



XMLObject 



The outermost XML element is the root of the object, so the first top-level property within our 
oCopyri ght object above is the date element: 



Of course, as with other JavaScript objects, you won't be able to use object dot-notation successfully 
when an element tag name contains any characters that would confuse JavaScript. For example: 

var oXML = <author> 

<first-name>Danny</first-name> 
</author> ; 

var sText = oXML[ ' f i rst-name ' ] ; // result: Darny 

var sText = oXML . fi rst-name ; // result: JavaScript stops cold! 

In the preceding example, JavaScript attempts to subtract the value of a variable called name from the 
value of the XML element oXML. first. If either one doesn't exist or if they do exist but don't both 
have numerical values that can be subtracted, JavaScript fails. The moral of the story: if you want to 
use dot notation and you are guaranteed to have complete control over the elements' tag names, you 
can restrict their character set to alphanumencs and underscores. If you're working with data coming 
in from a source that you might not always control, use bracket-quote notation, which will always 



Adding elements 

The appendChild( ) method of the XML object works similarly to the DOM method of the same 
name, inserting a child element into the referent: 

var oBook = <book/>; 
var oAuthor = <author/>; 
oBook.appendChild(oAuthor) ; 

result: <book> 

<author/> 
</book> 

Elements can also be appended to an XML element using the same concatenation syntax that we 
typically use with strings: 

oCopyright += <addendum>Al 1 rights reserved . </addendum> ; 
This results in: 

<copy right) 

<date>2010</date> 

<author>Danny Goodman</author> 
</copy right); 

<addendum>Al 1 rights reserved . <addendum> 
In order to insert the new element inside the copyri ght element, we need to write: 

oCopyri ght . author += <addendum>Al 1 rights reserved . </addendum> ; 



al ert(oCopyright.name( ) ) ; 
alert(oCopyright.child(0) .name( )) ; 
alert(oCopy right. date) ; 



// result = 'copyright' 
/ / resul t = ' date ' 
// result = '2010' 



succeed. 



365 



Part III: JavaScript Core Language Reference 



XMLObject 

resulting in: 

<copyright> 

<date>2010</date> 

<author>Danny Goodman</author> 

<addendum>Al 1 rights reserved . <addendum> 
</copy right) 

Embedded JavaScript expressions 

E4X becomes really exciting when you want the XML object to dynamically interact with JavaScript 
expressions. You do this with curly braces: 

va r oDate = new Date ( ) ; 

var oCopyright = <copyright> 

<date>{oDate. get Ful 1 Year( ) }</date> 
<author>Danny Goodman</author> 
</copyright>; 

Whatever is inside the curly braces is evaluated as a JavaScript expression and its result plugged into 
the XML stream. In the year 2020, the preceding example will resolve to: 

<copyright> 

<date>2020</date> 

<author>Danny Goodman</author> 
</copyright>; 

XML element attributes 

Just as in XML documents, the elements in your XML objects can have attributes. Those attribute val- 
ues can be set dynamically with curly brace notation as well. You can extract the value of an element's 
attribute by using dot notation with the @ operator in front of the attribute name, as we do with the 
1 ocati on attribute in this example: 

var oPhonebook = <phonebook> 
<entry> 

<name>Janis Jopl i n</name> 

<phone location="home">123-456-7890</phone> 
</entry> 
</phonebook> ; 

oPhonebook . entry . name + "'s " 

+ oPhonebook . entry . phone .@1 ocati on + " phone is " 
+ oPhonebook . entry . phone + 

oPhonebookf ' entry '][' name ' ] + "'s " 

+ oPhonebook[ ' entry '][' phone '][ '©type ' ] + " phone is " 
+ oPhonebook[ ' entry '][' phone ' ] + 

Jam's Joplin's home phone is 123-456-7890. 



var sText = 

// or: 

var sText = 

// result == 



366 



Chapter 20: E4X - 



Native XML Processing 



XMLListObject 

You can also use the @ notation to create and modify attribute values: 
oPhonebook . entry . phone .01 ocati on = "work"; 

The XMLList object 

Most XML documents contain repeating sets of elements. You can create such sets in your XML object 
simply by repeating a tag name for elements with the same parent: 

var oBook = <book> 

<title>The JavaScript Bible 7th Edi ti on</ti tl e> 
<author>Danny Goodman</author> 
<coauthor>Michael Morrison</coauthor> 
<coauthor>Paul Novitski</coauthor> 
<coauthor>Cynthi a Gustaff Rayl </coauthor> 
</book> ; 

When you point to the repeating set, you get back an XMLLi st object. It can be processed almost 
the same as you would an array. There are two primary differences: 1 ength ( ) is a method and 
not a property, and therefore requires the parentheses ( ); and other Array object methods are not 
supported by XMLList. 

var sText = "The number of co-authors is " + oBook. coauthor. 1 ength ( ) + 

In our current example XML, oBook. coauthor comprises a list within the overall data structure 
because there is more than one sibling element with the same tag name. 

// extract the XMLList of coauthor elements 
var oCoauthors = oBook . coauthor ; 

var sText = oBook. title + ' was written by ' + oBook. author + ' with '; 

// loop through co-authors 
var sConj = ' ' ; 

var iCoauthors = oCoauthors . 1 ength( ) ; 

var sLastAuthor = oCoauthors[iCoauthors-l] ; 

for (var i=0; i < iCoauthors; i++) 

{ 

// comma before item if more than two items 

if (i > 0 && iCoauthors > 2) 

{ 

sConj = ' , ' ; 

1 

// 'and' before item if last in a series 
if (i == iCoauthors-1 && iCoauthors > 1) 

{ 

sConj += ' and ' ; 

1 

/ / add i tern to 1 i st 

sText += sConj + oCoauthorsfi ] ; 

) 



367 



Part III: JavaScript Core Language Reference 



XMLListObject 

sText += ' . ' ; 

// result == The JavaScript Bible 7th Edition was written by Danny Goodman 
with Michael Morrison, Paul Novitski, and Cynthia Gustaff Rayl . 

The asterisk (*) can be used to represent all items in a collection. Using the preceding XML: 

var i Count = oBook.*.length(); 
The result is 5 — the root parent has a title, an author, and three coauthor elements. 

Adding list items 

To add a new item to an XML Li st, use the same concatenation syntax as mentioned above and name 
the list by its repeating element: 

oBook . coauthor += <coauthor>John Lennon</coauthor> ; 
resulting in: 

<book> 

<title>The JavaScript Bible 7th Edi ti on</ti tl e> 
<author>Danny Goodman</author> 
<coauthor>Michael Morrison</coauthor> 
<coauthor>Paul Novitski </coauthor> 
<coauthor>Cynthi a Gustaff Rayl </coauthor> 
<coauthor>John Lennon</coauthor> 
</book> 

Note 

A cautionary note: if you extract an XML Li st object from an XML object as we did above: 

// extract the XMLList of coauthor elements 
var oCoauthors = oBook.c oauthor; 

the list is a static copy of the XML elements with no dynamic linkage. Any subsequent change to either the XML 
object or the XML Li st object will not be reflected in the other. In this example, adding a new coauthor 
element to the oCoauthors list does not modify the original XML object. ■ 

Selecting list items 

The power of E4X really shines in its ability to select XMLList items based on attributes and values. 
Consider the following example: 

var oPhonebook = <phonebook> 
<entry> 

<name>Janis Jopl i n</name> 

<phone location="home">123-456-7890</phone> 
<phone location="work">2 34-567 -8901</phone> 
<phone location="cell ">345-678-9012</phone> 

</entry> 

<entry> 



368 



Chapter 20: E4X - 



Native XML Processing 



XMLListObject 

<name>John Lennon</name> 

<phone 1 ocati on = " home " > 9 8 7 -654-32 10</phone> 
<phone location="work">876-543-2109</phone> 
</entry> 
</phonebook> ; 

We've seen that we can select a list of all elements of a matching name quite easily: 

// extract a list of all the phone elements 
var oPhones = oPhonebook . entry . phone ; 



res ul t : 












<phone 


1 o c a t i o n = 


'home" 


>123 


-456 


-7890</phone> 


<phone 


1 o c a t i o n = 


'work" 


>234 


-567 


-8901</phone> 


<phone 


1 o c a t i o n = 


'eel 1 " 


>345 


-678 


-9012</phone> 


<phone 


1 o c a t i o n = 


'home" 


>987 


-654 


-3210</phone> 


<phone 


1 o c a t i o n = 


'work" 


>876 


-543 


-2109</phone> 



Note that this finds the phone elements in more than one entry record. The selection statement 
essentially says, "Find all the phone elements whose parent is a root entry element." If we wanted 
to limit the search to a single entry element, we need only specify its index: 

var oPhones = oPhonebook . entry [0] . phone ; 
Similarly, we can select elements by attribute value: 

var oWorkPhones = oPhonebook . entry . phone . (@1 ocati on == 'work'); 

res ul t : 

<phone 1 ocati on=" work ">2 34 -567-8901</phone> 
<phone 1 ocati on=" work ">876-543-2109</phone> 

This narrows the selection to just those phone elements that have a type attribute of "work" — when 
the expression in parentheses evaluates to true. Note that we're using the double equal sign == of an 
equality comparison, not the single = of a value assignment! 

One of the handy aspects of this syntax is being able to extract the value of one element after search- 
ing for its sibling: 

var oPhone = oPhonebook . entry .( name == 'Jam's Jopl i n '). phone . 
(@1 ocati on == ' home ' ) ; 

resul t : 

<phone 1 oca t i on=" home ">1 23 -456 -7890</ phone) 

The selector says, "Get me the home phone number of the entry with the name 'Janis Joplin.'" The 
statement locates an entry with a child element name that has the value 'Jani s Jopl i n' but then 
returns a phone element that is the sibling of the name element. Is that cool or what? Of course, like 
so many dead rock stars, Janis currently has an unlisted number, but we can always dream. 

XML selector expressions can contain JavaScript functions, and without having to use curly brace 
syntax: 

function checkExchangetsExchange, sPhone) 

{ 



369 



Part III: JavaScript Core Language Reference 



X/Vf£Ob/ecf.child() 

sExchange = '-' + sExchange + 

return (sPhone.indexOf(sExchange) > 0); 

} 

var sPhone = oPhonebook . entry .( checkExchanget ' 543 ' , phone. 
(@1 oca tion=='work' ))) .name; 

This returns "John Lennon" since we've selected the entry in which the checkExchange( ) function 
returns true. 

Serializing XML objects 

XML can be a handy format for keeping track of information within a script, but its primary use is 
communicating structured data between programs. To send an XML structure to the server, we trans- 
late the JavaScript object into a text string. The XML object has two interchangeable methods for doing 
this — toXMLString( ) and toString( ) .These methods can operate on any subset of the object 
as well as the whole thing at once: 

var sXMLText = oPhonebook . toXMLStri ng () ; 

var sXMLText = oPhonebook . entry .( name == 'John Lennon '). toStri ng( ) ; 

Embedding E4X in HTML 

Although you can use the standard MIME type with E4X 
<script type="text/javascript"> 

you might end up with inexplicable syntax errors. This usually occurs for one of two reasons: you are 
using HTML comments to hide script from older browsers; or you are putting your scripts into XML 
CDATA sections. If either of these is the case, then you can add the E4X argument to the standard 
MIME type: 

<script type="text/javascript;e4x=l"> 

Methods 

childO 

Returns: XML object 

Compatibility: WmIE5-, MacIE-, NN-, FF3.5+, Safari-, Opera-, Chrome- 

The c h i 1 d ( ) method returns an XML element that is an immediate descendant of the referent: 

var oPhonebook = <phonebook> 
<person> 

<name>Janis Jopl i n</name> 

<phone locati on = " home" >123-456-7890</phone> 
</person> 
</phonebook> ; 

alert(oPhonebook. person. child(l) ) ; // result = '123-456-7890' 



370 



Chapter 20: E4X — Native XML Processing 



XMLObjeclnameQ 

Remember that c h i 1 d ( ) is a method, even though we use it much as we would an array, so use 
parentheses around the index, not brackets. Like an array, the chi 1 d ( ) collection is a zero-based list, 
so chi 1 d ( 1 ) finds the second child element. Unlike an array, we cannot use for Each syntax. 

Related Item: childNodes( ) DOM property 

copy( ) 

Returns: XML object 

Compatibility: WmIE5-, MacIE-, NN-, FF3.5+, Safari-, Opera-, Chrome- 

The copy( ) method returns a deep copy of the selected portion of an XML object. For example: 

var oPhonebook = <phonebook> 
<person> 

<name>Janis Jopl i n</name> 

<phone locati on = " home" >123-456-7890</phone> 
</person> 
</phonebook> ; 

var oPerson = oPhonebook . person . copy () ; 

The result of this operation is the following XML object: 

<person> 

<name>Janis Jopl i n</name> 

<phone locati on="home">123-456-7890</phone> 
</person> 

Note that this can also be accomplished using a simple assignment statement: 
var oPerson = oPhonebook . person ; 

name( ) 

Returns: String 

Compatibility: WmIE5-, MacIE-, NN-, FF3.5+, Safari-, Opera-, Chrome- 
The name( ) method returns a string that is the XML element's tag name: 

var oPhonebook = <phonebook> 
<person> 

<name>Janis Jopl i n</name> 

<phone locati on="home">123-456-7890</phone> 
</person> 
</phonebook> ; 



al ert ( oPhonebook . 
al ert(oPhonebook, 
al ert(oPhonebook. 



chi 1 d ( 0 ) . name( ) ) ; // result = 'person' 

person . chi 1 d( 1 ). name( )) ; // result = 'phone' 
person. child(D); // result = '123-456-7890' 



371 



Part III: JavaScript Core Language Reference 



X/Vf£Ob/ecf.toString() 

Remember that c h i 1 d ( ) is a method, even though we use it much as we would an array, so use 
parentheses around the index, not brackets. Like an array, the chi 1 d ( ) collection is a zero-based list, 
so child(l) finds the second child element. 

Related Item: childNodes( ) DOM property 

toStringO, toXMLStri ng( ) 

Returns: String 

Compatibility: WmIE5-, MacIE-, NN-, FF1.5+, Safari-, Opera-, Chrome- 

The toStri ng ( ) and toXMLStri ng( ) methods return a string that is the concatenated text of all 
the text nodes of the XML object. 

Related Item: string. toStringO 



372 



Control Structures \, 
and Exception Handling 




You get up in the morning, go about your day's business, and then end 
the day by walking the dog, changing into comfy footwear, and relax- 
ing. That's not much different from what a program does from the time 
it starts to the time it ends. But along the way, both you and a program take lots 
of tiny steps, not all of which advance the processing in a straight line. At times, 
you have to control what's going on by making a decision or repeating tasks until 
the whole job is finished. Control structures are the facilities that make these 
tasks possible in JavaScript. 

Control structures in JavaScript follow along the same lines as they do in many 
programming languages. Basic decision-making and looping constructions satisfy 
the needs of just about all programming tasks. 

Another vital program control mechanism — error (or exception) handling — is 
formally addressed in the ECMA-262 language standard. The concept of excep- 
tion handling was added to the JavaScript version introduced in IE5.5 and NN6, 
but it is well known to programmers in many other environments. Adopting 
exception-handling techniques in your code can greatly enhance recovery from 
processing errors beyond your control, such as those caused by errant user input 
or network glitches. 



IN THIS CHAPTER 



Branching script execution 
down multiple paths 

Looping through ordered 
collections of data 

Applying exception handling 
techniques 



If and If. . .Else Decisions 



Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome+ 

JavaScript programs frequently have to make decisions based on the current val- 
ues of variables or object properties. Such decisions can have only two possible 
outcomes at a time. The factor that determines the path that the program takes 
at these decision points is if a statement evaluates to true or false. For example, 
when you come back from walking the dog at night, the statement under test is 
something such as, "Is my comfy footwear in the living room?" If that statement 
is false, you look for your comfy footwear; if that statement is true, you put on 
your comfy footwear and relax. 



373 



Part III: JavaScript Core Language Reference 



if 

Simple decisions 

JavaScript syntax for this kind of simple decision always begins with the keyword i f , followed by the 
condition to test, and then the statements that execute if the condition yields a true result. JavaScript 
uses no "then" keyword (as some other languages do); the keyword is implied by the way parentheses 
and braces surround the various components of this construction. The formal syntax is: 

if (condition) 

{ 

statements I f True 

I 

This construction means that if the condition is true, program execution takes a detour to execute 
statements inside the braces. No matter what happens, the program continues executing statements 
beyond the closing brace ()). If a comfy footwear search were part of the scripting language, the code 
would look like this: 

if ( comfy Footwea r I n Li vi ngRoom == false) 

{ 

look for them 

} 

If you're not used to C/C++, the double equals sign may have caught your eye. You learn more about 
this type of operator in the next chapter, but for now, know that this operator compares the equality 
of items on either side of it. In other words, the condition statement of an if construction must 
always yield a Boolean (tnue or false) value. Some object properties, you may recall, are Booleans, 
so you can stick a reference to that property into the condition statement by itself. Otherwise, the 
condi ti on statement consists of two values separated by a comparison operator, such as == (equals) 
or ! = (does not equal). 

Next, look at some real JavaScript. The following function receives a text input object: 

function notTooHigh(oInput) 
{ 

if ( parseint ( olnput . val ue ) > 100) 
{ 

alertC'Sorry, the value you entered is too high. Try again."); 
return false; 

( 

return true; 

} 

The condition (in parentheses) tests the contents of the field against a hard- wired value of 100. If 
the entered value is larger than that, the function alerts you and returns a fal se value to the calling 
statement elsewhere in the script. But if the value is less than 100, all intervening code is skipped and 
the function returns true. 

About (condition) expressions 

A lot of condition testing for control structures compares a value against some very specific condition, 
such as a string being empty or a value being null. You can use a couple of shortcuts to take care of 
many circumstances. Table 21-1 details the values that evaluate to true or fal se (or equivalent) to 
satisfy a control structure's condition expression. 



374 



Chapter 21 : Control Structures and Exception Handling 



if . . . else 



TABLE 21-1 



Condition Value Equivalents 


True 


False 


Nonempty string 


Empty string 


Nonzero number 


0 


Nonnull value 


null 


Object exists 


Object doesn't exist 


Property is defined 


Undefined property 



Instead of having to spell out an equivalency expression for a condition involving these kinds of 
values, you can simply supply the value to be tested. For example, if a variable named myVal is 
capable of reaching an i f construction with a value of n u 1 1 , an empty string, or a string value for 
further processing, you can use the following shortcut: 

i f (myVal ) 
{ 

// do processing on myVal 

} 

All nul 1 or empty string conditions evaluate to fal se, so that only the cases of myVal being a 
processable value get inside the 1 f construction. This mechanism is the same that you have seen 
elsewhere in this book to employ object detection for browser branching. For example, the code 
nested inside the following code segment executes only if the document object has an images array 
property: 

if ( document . i mages ) 
{ 

// do processing on image objects 

} 



Complex decisions 

The simple type of i f construction described earlier is fine when the decision is to take a small detour 
before returning to the main path. But not all decisions — in programming or in life — are like that. 
To present two alternate paths in a JavaScript decision, you can add a component to the construction. 
The syntax is 

if (condition) 

II statementslff rue 

else 

// statementslf Fal se 



375 



Part III: JavaScript Core Language Reference 



if . . . else 

By appending the else keyword, you give the i f construction a path to follow in case the condition 
evaluates to false. The statements I f True and statementslf Fal se do not have to be balanced 
in any way: One statement can be one line of code, the other 100 lines. But when either one of those 
branches completes, execution continues after the last closing brace. To demonstrate how this con- 
struction can come in handy, the following example is a script fragment that assigns the number of 
days in February based on whether or not the year (the Date object is explained in Chapter 17) is a 
leap year (using modulo arithmetic, explained in Chapter 22, to determine if the year is evenly divisi- 
ble by four, and setting aside all other leap year calculation details for the moment): 

var howMany = 0; 

var currentTime = new Date(); 

var theYear = currentTime . getFul 1 Year( ) ; 

if (theYear % 4 == 0) 

{ 

howMany = 29; 

} 

else 
{ 

howMany = 28; 

} 

Here is a case where execution has to follow only one of two possible paths to assign the number of 
days to the howMany variable. Had the el se portion not been used, as in 

var howMany = 0; 

var currentTime = new Date(); 

var theYear = currentTime . getFul 1 Year( ) ; 

if (theYear % 4 == 0) 

{ 

howMany = 29; 

) 

howMany = 28; 

then the variable would always be set to 28, occasionally after momentarily being set to 29. The else 
construction is essential in this case. However, by initializing your variable to 28, it is possible to 
achieve the correct end without the else portion, as in 

var howMany = 28; 

var currentTime = new Date(); 

var theYear = cur rentTi me . get Ful 1 Yea r ( ) ; 

if (theYear % 4 == 0) 

{ 

howMany = 29; 

} 



Nesting if. . .else statements 

Designing a complex decision process requires painstaking attention to the logic of the decisions your 
script must process and the statements that must execute for any given set of conditions. The need for 
repetitive logic disappeared with the advent of switch construction in version 4 browsers (described 
later in this chapter), but there may still be times when you must fashion complex decision behavior 



376 



Chapter 21 : Control Structures and Exception Handling 



if . . . else 

out of a series of nested if. . .else statements. Without a JavaScript-aware text editor to help 
keep everything properly indented and properly terminated (with closing braces), you have to monitor 
the authoring process very carefully. Moreover, the error messages that JavaScript provides when a 
mistake occurs (see Chapter 48, "Debugging Scripts," on the CD-ROM) may not point directly to the 
problem line, but only to the region of difficulty. 

To demonstrate a nested set of i f . . .else constructions, Listing 21-1 presents a simple user 
interface to a complex problem. A single text object asks the user to enter one of three letters — A, 
B, or C. The script behind that field processes a different message for each of the following conditions: 

• The user enters no value . 

• The user enters A. 

• The user enters B. 

• The user enters C. 

• The user enters something entirely different. 



Note 

The function to assign event handlers throughout the code in this chapter and much of the book is 
addEvent( ), a cross-browser event handler explained in detail in Chapter 32: See "A cross-browser event 
binding solution." ■ 



What's with the Formatting? 

Indentation of the i f construction, and the further indentation of the statements executed on a true 
condition, are not required by JavaScript. What you see here, however, is a convention that most 
JavaScript scripters follow. As you write the code in your text editor, you can use the Tab key to establish 
each level of indentation; some developers prefer using a setting in their editor that converts tabs to 
spaces, which guarantees that indentations are consistent across different editors. The browser ignores 
these tab characters (and/or spaces) when loading your scripts. 

There are many styles of indenting. The style we use most often in this book is known as Allman — in 
which opening and closing braces occupy their own lines — while many programmers prefer 1TBS 
(The One True Brace Style), in which the opening brace is on the same line as the control statement. 



LISTING 21-1 



Nested if. . .else Constructions 

HTML: jsb-21-01.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<title>Nested if. . .else</title> 

<script type=" text /javascript" src=". . / jsb-gl obal .js"X/script> 

continued 



377 



Part III: JavaScript Core Language Reference 



if . . . else 

(continued) 



LISTING 21-1 



<script type="text/ j avascri pt" src=" j sb-21 -01 . j s "></scri pt> 
</head> 
<body> 

<hl>Nested if. . .else</hl> 

<form id="theForm" acti on="val i date . php" method="get"> 
<f i el dset> 

< 1 a be 1 f or="theText">Pl ease enter A, B, or C: < / 1 a be 1 > 
<input id="theText" type="text"> 
<input type="submi t"> 
</fieldset> 
</ form) 
</body> 
</html > 

JavaScript: jsb-21-01.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// add an event to the form 

add Even t( document . get El erne nt By Id ( ' the Form ') , 'submit', 
suppressFormSubmission) ; 

// add an event to the input box 

addEvent ( document . get El ementBy Id ( ' theText ' ) , 'change', test Letter) 



function suppress FormSubmissi on (evt) 
{ 

// consolidate event handling 

if (!evt) evt = wi ndow . event ; 

// cancel default behavior 

// W3C DOM method (hide from IE) 

if ( evt . preventDef aul t ) evt . preventDef aul t ( '. 

// IE method 
return false; 



function testLetterO 
{ 

// assign to shorter variable name 
var i npVal = thi s . val ue ; 

if (inpVal != "") 

( // if entry is not empty then dive in... 



378 



Chapter 21 : Control Structures and Exception Handling 



if (inpVal == "A") 
( // Is it an "A"? 

al ert( "Thanks for the A."); 

else if (inpVal == "B") 
{ // No. Is it a " B " ? 

al ert( "Thanks for the B."); 

else if (inpVal == "C") 
( // No. Is it a "C"? 

al ert( "Thanks for the C."); 

el se 

{ // Nope. None of the above 

al ert( "Sorry , wrong character or case."); 

} 

el se 

{ // value was empty, so skipped all other stuff above 
alert("You did not enter anything."); 

} 



Each condition executes only the statements that apply to that particular condition, even if it takes 
several queries to find out what the entry is. You do not need to break out of the nested construction, 
because when a true response is found, the relevant statement executes, and no other statements 
occur in the execution path to run. 

You might have noticed the acti on on the form element identifies a PHP script called val i date 
. php. In Chapter 7, "Scripts and HTML Documents," we talked about the advisability of always 
specifying a server-side program in case the user has turned off JavaScript. 



Conditional Expressions 

Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome+ 

While we're showing you decision-making constructions in JavaScript, now is a good time to intro- 
duce a special type of expression that you can use in place of an i f . . . e I s e control structure for a 
common type of decision — the instance where you want to assign one of two values to a variable, 
depending on the outcome of some condition. The formal definition for the conditional expression is 
as follows: 

variable = [condition) ? vail : va!2; 

This expression means that if the Boolean result of the condi ti on statement is true, JavaScript 
assigns vail to the variable; otherwise, it assigns val 2 to the variable. Like other instances of condi- 
tional expressions, this one must also be written inside parentheses. The question mark is key here, as 
is the colon separating the two possible values. 



379 



Part III: JavaScript Core Language Reference 



switch 

A conditional expression, though not particularly intuitive or easy to read inside code, is very 
compact. Compare an if. . .else version of an assignment decision that follows 

var col 1 ectorStatus ; 
if (CDCount > 500) 
{ 

col 1 ectorStatus 

1 

else 
1 

col 1 ectorStatus 

) 

with the conditional expression version: 

var col 1 ectorStatus = (CDCourt > 500) ? "fanatic" : "normal"; 

The latter saves a few code lines, although the internal processing is the same as that of an 
if. . .else construction. Of course, if your decision path contains more statements than just one 
setting the value of a variable, the if. . .else or switch construction is preferable. This shortcut, 
however, is a handy one to remember if you need to perform binary actions, such as setting a 
true-or-false flag in a script. 

The switch Statement 



Compatibility: WinIE4+, MacIE4+, NN4+, Moz4-, Safari+, Opera4-, Chrome+ 

In some circumstances, a binary — true or false — decision path is not enough to handle the process- 
ing in your script. An object property or variable value may contain any one of several values, 
and a separate execution path is required for each one. The most obvious way to establish such a 
decision path is with a series of i f . . . e 1 s e constructions. However, in addition to quickly getting 
unwieldy with nested code, the more conditions you must test, the less efficient the processing is, 
because each condition must be tested. The end result is a sequence of clauses and braces that can get 
very confusing. 

Starting in version 4 browsers, a control structure in use by many languages was introduced to 
JavaScript. The implementation is similar to that of PHP, Java, and C/C++, which use the swi tch 
and case keywords. The basic premise is that you can create any number of execution paths based 
on the value of some expression. At the beginning of the structure, you identify what that expression 
is and then, for each execution path, assign a label matching a particular value. 

The formal syntax for the switch statement is as follows: 

switch ( expressi on) 

{ 

case labell: 

[statements^ 

[break; ] 
case label2: 

[statements^ 

[break; ] 



= "fanatic"; 



= "normal " ; 



380 



Chapter 21 : Control Structures and Exception Handling 



switch 

[def a ul t : 

statements^ 

) 



For example: 



swi tch ( Time 
{ 

case ' mor 
mea I = 
break ; 



Of Day) 

ni ng' : 
' breakfast ' ; 



case 'midday': 
mea I = 'lunch'; 
break ; 



case 'aft 
case 'eve 
mea I = 
break ; 



ernoon ' : 
ni ng' : 
'dinner' ; 



def aul t : 
mea l 



'fast ' , 



The expression parameter of the switch statement can evaluate to any string or number value . 
Labels are surrounded by quotes when the labels represent string values of the expression. Notice 
that the break statements are optional. A break statement forces the switch expression to bypass 
all other checks of succeeding labels against the expression value. It's important to understand that 
without a break statement at the end of each case, every line of code in the switch expression 
will get executed. However, since Boolean operators are not allowed (each label must be for one and 
only one value), you can use careful placement of the break statement. (In the preceding example, 
if the time of day is either afternoon or evening, the meal is dinner.) Another option is the def aul t 
statement, which provides a catchall execution path when the expression value does not match any 
of the case statement labels. If you'd rather not have any execution take place with a non-matching 
expression value, omit the default part of the construction. 



To demonstrate the syntax of a working switch statement, Listing 21-2 provides the skeleton of a 
larger application of this control structure. The page contains two separate arrays of different product 
categories. Each product has its name and price stored in its respective array. A sel ect list displays 
the product names. After a user chooses a product, the script looks up the product name in the appro- 
priate array and displays the price. 



The trick behind this application is the values assigned to each product in the select list. While the 
displayed text is the product name, the val ue attribute of each <opti on> tag is the array category 
for the product. That value is the expression used to decide which branch to follow. Notice, too, that 
we assign a label to the entire switch construction. The purpose of that is to let the deeply nested 
repeat loops for each case completely bail out of the switch construction (via a labeled break state- 
ment) whenever a match is made. You can extend this example with any number of product category 
arrays with additional case statements to match. 



381 



Part III: JavaScript Core Language Reference 



switch 



LISTING 21-2 



The switch Construction in Action 

HTML: jsb-21-02.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Swi tch Statement and Labeled Break</ti tl e> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb-21 -02 . j s "></scri pt> 

</head> 

<body> 

<hl>Switch Statement and Labeled Break</hl> 

<p>Select a chip for lookup in the chip price table:</p> 

<form id="theForm" acti on="val i date . php" method="get"> 

<P> 

< 1 a be 1 for=" chips ">Chip:</label> 
<select id="chips"> 
<opti on></ opti on> 

<option val ue=" ICs ">Septi urn 900MHz</opti on> 
<option val ue=" ICs ">Septi urn Pro 1 . 0GHz</opti on> 
<option val ue=" ICs ">0cti urn BFD 750MHz</opti on> 
<option val ue="snacks">Rays Potato Chi ps</opti on> 
<option val ue= " snacks ">Cheezey-ettes</ opti on> 
<option val ue="snacks">Torti 1 1 a Fl ats</opti on> 
<opti on>Poker Chi pset</opti on> 
</sel ect> 

< 1 a be 1 f or="cost">&nbsp ; Pri ce : </l abel > 
<input type="text" id="cost" size="10"> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-2102.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// add an event to the drop down list 

addEvent( document . getEl ementBy Id (' chi ps ') , 'change', getPrice); 

} 

// build two product arrays with a custom object, simulating two database tables 



382 



Chapter 21 : Control Structures and Exception Handling 



switch 

function product( name , price) 
{ 

this. name = name; 
this. pri ce = pri ce ; 

} 

var ICs = new Array ( ) ; 

ICs[0] = new product( "Septi urn 900MHz", "$149"); 
ICs [ 1] = new product( "Septi urn Pro 1.0GHz", "$249"); 
I Cs [ 2] = new product ( "Octi urn BFD 750MHz", "$329"); 

var snacks = new ArrayO; 

snacks[0] = new product( "Rays Potato Chips", "$1.79"); 
snacks[l] = new product( "Cheezey-ettes" , "$1.59"); 
snacks[2] = new product ( "Torti 1 1 a Flats", "$2.29"); 

// lookup in the 'table' the cost associated with the product 

f uncti on getPri ce ( ) 

{ 

var chipName = thi s . opti ons [thi s . sel ectedl ndex] . text ; 
var chipType = thi s . opti ons [thi s . sel ectedl ndex] . val ue ; 
var outField = document . getEl ementBy Id (' cost ') ; 



master : 

switch(chipType) 
{ 

case "ICs": 

for (var i = 0; i < ICs. length; i++) 
{ 

if ( ICs [i ]. name == chipName) 
{ 

outFi el d . val ue = ICs [ i ] . pri ce ; 
break master; 



break; 
case "snacks": 

for (var i = 0; i < snacks . 1 ength ; i++) 
{ 

if ( snacks [ i ]. name == chipName) 
{ 

outFi el d . val ue = snacks [ i ]. pri ce ; 
break master; 



break; 
def aul t : 

outFi el d . val ue = "Not Found"; 



383 



Part III: JavaScript Core Language Reference 



for 

Repeat (for) Loops 

Compatibility: WinIE3+, MacIE3+, NN2+, Moz+, Safari+, Opera+, Chrome + 

As you have seen in numerous examples throughout other chapters, the capability to cycle through 
every entry in an array or through every item of a form element is vital to many JavaScript scripts. 
Perhaps the most typical operation is inspecting a property of many similar items in search of a spe- 
cific value, such as to determine which radio button in a group is selected. One JavaScript structure 
that allows for these repetitious excursions is the for loop, so-named after the keyword that begins 
the structure. Two other structures, the whi 1 e loop and the do-whi 1 e loop, are covered in the 
following sections. 

The JavaScript for loop repeats a series of statements any number of times and includes an optional 
loop counter that can be used in the execution of the statements. The following is the formal syntax 
definition: 

for ( [initial expression}; Lcondi ti on} ; [update expression]) 

{ 

statements 

} 

The three statements inside the parentheses (parameters to the for statement) play a key role in the 
way a for loop executes. 

An initial expression in a for loop is executed one time, the first time the for loop begins to run. 
The most common application of the initial expression is to assign a name and starting value to a 
loop counter variable. Thus, seeing a v a r statement that both declares a variable name and assigns 
an initial value (generally 0 or 1) to it is not uncommon. An example is 

v a r i = 0 ; 

You can use any variable name, but conventional usage calls for the letter i , which is short for index. 
If you prefer the word counter or another word that reminds you of what the variable represents, 
that's fine, too. In any case, the important point to remember about this statement is that it executes 
once at the outset of the for loop. 

The second statement is a condition, precisely like the condition statement you saw in i f construc- 
tions earlier in this chapter. When a loop-counting variable is established in the initial expression, the 
condition statement usually defines how high the loop counter should go before the looping stops. 
Therefore, the most common statement here is one that compares the loop counter variable against 
some fixed value — is the loop counter less than the maximum allowed value? If the condition is false 
at the start, the body of the loop is not executed. But if the loop does execute, then when execution 
comes back around to the top of the loop, JavaScript reevaluates the condition to determine the cur- 
rent result of the expression. If the loop counter increases with each loop, eventually the counter value 
goes beyond the value in the condi ti on statement, causing the condi ti on statement to yield a 
Boolean value of f al se. The instant that happens, execution drops out of the for loop entirely. 

The final statement, the update expression, is executed at the end of each loop execution — after all 
statements nested inside the for construction have run. Again, the loop counter variable can be a 
factor here. If you want the counter value to increase by one the next time through the loop (called 
incrementing the value), you can use the JavaScript operator that makes that happen: the ++ operator 
appended to the variable name. That task is the reason for the appearance of all those i ++ symbols in 
the for loops that you've already seen in this book. You're not limited to incrementing by one. You 



384 



Chapter 21: Control Structures and Exception Handling 



for 

can increment by any multiplier you want, or even drive a loop counter backward by decrementing 
the value (i --). 

Now, take this knowledge and beef up the formal syntax definition with one that takes into account a 
typical loop-counting variable, i , and the common ways to use it: 

//incrementing loop counter 

for (var i = minValue; i <= maxValue; i++) 

{ 

// statements 

} 

//decrementing loop counter 

for (var i = maxValue; i >= minValue; i--) 

{ 

// statements 

} 

In the top loop counter, the variable, i , is initialized at the outset to a value equal to that of 
mi nVal ue. Variable i is immediately compared against maxVal ue. If i is less than or equal to 
maxVal ue, processing continues into the body of the loop. At the end of the loop, the update expres- 
sion executes. The value of i is incremented by 1. Therefore, if i is initialized as 0, then the first time 
through the loop, the i variable maintains that 0 value during the first execution of statements in the 
loop. The next time around, the variable has the value of 1. 

As you may have noticed in the formal syntax definition, each of the parameters to the for statement 
is optional. For example, the statements that execute inside the loop may control the value of the loop 
counter based on data that gets manipulated in the process. Therefore, the update statement would 
probably interfere with the intended running of the loop. But we suggest that you use all three param- 
eters until such time as you feel absolutely comfortable with their roles in the for loop. If you omit 
the condition statement, for instance, and you don't program a way for the loop to exit on its own, 
your script may end up in an infinite loop — which does your users no good. 

Putting the loop counter to work 

Despite its diminutive appearance, the i loop counter (or whatever name you want to give it) can be a 
powerful tool for working with data inside a repeat loop. For example, examine a version of the classic 
JavaScript function that creates an array while initializing entries to a value of 0 : 

// initialize array with n entries 

function MakeArray(n) 

{ 

this. length = n; 

for (var i = 0; i < n; i++) 

{ 

this[i] = 0; 

} 

return this; 

} 

The loop counter, i , is initialized to a value of 0 because the first element of any JavaScript array 
is element zero. In the condition statement, the loop continues to execute as long as the value of 
the counter is less than the number of entries being created (n). (For example, if n is 10, the array 



385 



Part III: JavaScript Core Language Reference 



for 

is initialized with ten elements, 0-9.) After each loop, the counter increments by 1. In the nested 
statement that executes within the loop, you use the value of the i variable to substitute for the index 
value of the assignment statement: 

this[i] = 0; 

The first time the loop executes, the value expression evaluates to 

this[0] = 0; 
The next time, the expression evaluates to 

this[l] = 0; 
and so on, until all n entries are created and stuffed with 0. 

Recall the HTML page in Listing 18-2, where a user chooses a regional office from a sel ect list (trig- 
gering a script to look up the manager's name and sales quota for that region). Because the regional 
office names are stored in an array, the page could be altered so that a script populates the select 
element's options from the array. That way, if there is ever a change to the alignment of regional 
offices, there need be only one change to the array of offices, and the HTML doesn't have to be modi- 
fied. As a reminder, here is the definition of the regional offices array, created while the page loads: 

var a Regi onal Of f i ces = ["New York", "Chicago", "Houston", "Portland"]; 

Code inside the external JavaScript file can be used to dynamically generate the select list as 
follows: 

for (var i = 0; i < aRegi onal Off i ces . 1 ength ; i++) 

{ 

oSel ect . opti ons [ i ] = new Opt i on ( a Regi onal Of f i ces [ i ] ) ; 

} 

// pre-select the first option 
oSel ect . opti ons [0] . sel ected = true; 

Notice one important point about the condition statement of the for loop: JavaScript extracts the 
length property from the array to be used as the loop counter boundary. From a code maintenance 
and stylistic point of view, this method is preferable to hard-wiring a value there. If the company 
added a new regional office, you would make the addition to the array "database," whereas every- 
thing else in the code would adjust automatically to those changes, including creating a longer pop-up 
menu in this case. 

Notice, too, that the operator for the condi ti on statement is less-than (<): The zero-based index 
values of arrays means that the maximum index value we can use is one less than the actual count 
of items in the array. This is vital information, because the index counter variable (i) is used as the 
index to the regionalOffices array each time through the loop to read the string for each item's 
entry. You also use the index of the first option (0) to add the selected attribute to the first option's 
definition. 

The utility of the loop counter in for loops often influences the way you design data structures, such 
as two-dimensional arrays (see Chapter 18, "The Array Object") for use as databases. Always keep 
"the loop-counter mechanism" in the back of your mind when you begin writing JavaScript script that 
relies on collections of data that you embed in your documents. 



386 



Chapter 21 : Control Structures and Exception Handling 



for 

Breaking out of a loop 

Some loop constructions perform their job as soon as a certain condition is met, at which point they 
have no further need to continue looping through the rest of the values in the loop counter's range. 
A common scenario for this is the cycling of a loop through an entire array in search of a single entry 
that matches some criterion. That criterion test is set up as an i f construction inside the loop. If 
that criterion is met, you break out of the loop and let the script continue with the more meaning- 
ful processing of succeeding statements in the main flow. To accomplish that exit from the loop, use 
the break statement. The following schematic shows how the break statement may appear in a 
for loop: 

for (var i = 0; i < array . I ength ; i++) 
{ 

if ( array[i ]. property == magicValue) 
{ 

// statements that act on entry array[i] 
break ; 

} 

} 

The break statement tells JavaScript to bail out of the nearest for loop (in case you have nested for 
loops). Script execution then picks up immediately after the closing brace of the for statement. The 
variable value of i remains whatever it was at the time of the break, so that you can use that variable 
later in the same script to access, say, that same array entry. 

A construction similar to this was used in Chapter 35, "Button Objects." There, the discussion of radio 
buttons demonstrates this construction, where, in Listing 35-6, you see a set of radio buttons whose 
value attributes contain screen sizes, in pixels. A function uses a for loop to find out which button 
was selected and then uses that item's index value — after the for loop breaks out of the loop — to 
alert the user. Listing 21-3 shows the relevant function. 



LISTING 21-3 



Breaking Out of a for Loop 

JavaScript: jsb-21-03. js 

function showMegapi xel s ( ) 
{ 

var theForm = document . getEl ementBy Id (' si zes Form ') ; 
if (theForm) 
{ 

var sizeChoices = theForm . choi ces ; 

for (var i = 0; i < si zeChoi ces . 1 ength ; i++) 

{ 

if ( si zeChoi ces [ i ]. checked ) 
{ 

break; 

) 

continued 



387 



Part III: JavaScript Core Language Reference 



while 



LISTING 21-3 



(continued) 



alert("That image size requires 
" mega pi xel s . " ) ; 



+ si zeChoi ces [i ] . val ue + 



In this case, breaking out of the for loop is more than a matter of mere efficiency; the value of the 
loop counter (frozen at the break point) is used to summon a different property outside of the for 
loop. Starting back in version 4 browsers, the break statement gained additional powers in coopera- 
tion with the new label feature of control structures. This subject is covered later in this chapter. 

Directing loop traffic with continue 

One other possibility in a for loop is that you may want to skip execution of the nested statements 
for just one condition. In other words, as the loop goes merrily on its way round and round, exe- 
cuting statements for each value of the loop counter, one value of that loop counter may exist for 
which you don't want those statements to execute. To accomplish this task, the nested statements 
need to include an i f construction to test for the presence of the value to skip. When that value is 
reached, the conti nue command tells JavaScript to immediately skip the rest of the body, execute 
the update statement, and loop back around to the top of the loop. 

To illustrate this construction, take a look at an artificial example that skips over execution when the 
counter variable is the superstitious person's unlucky 1 3 : 

for (var i = 0; i <= 20; i++) 

{ 

if (i == 13) 
{ 

conti nue ; 

} 

// statements 

} 

In this example, the statements part of the loop executes for all values of i except 13. The 
continue statement forces execution to jump to the i++ part of the loop structure, incrementing 
the value of 1 for the next time through the loop. In the case of nested for loops, a conti nue 
statement affects the for loop in whose immediate scope the i f construction falls. The conti nue 
statement was enhanced in version 4 browsers with the 1 abel feature of control structures, which is 
covered later in this chapter. 



The while Loop 

Compatibility: WinIE34-, MacIE34-, NN24-, Moz-I-, Safari-!-, Opera4-, Chrome4- 

The for loop is not the only kind of repeat loop you can construct in JavaScript. Another statement, 
called a whi 1 e statement, sets up a loop in a slightly different format. Rather than providing a mech- 
anism for modifying a loop counter, a whi 1 e repeat loop assumes that your script statements will 
reach a condition that forcibly exits the repeat loop. 



388 



Chapter 21 : Control Structures and Exception Handling 



while 

The basic syntax for a while loop is 

while (condition) 
I 

statements 

) 

The condition expression is the same kind that you saw in i f constructions and in the middle 
parameter of the f on loop. You introduce this kind of loop if some condition exists in your code 
(evaluates to true) before reaching this loop. The loop then performs some action, which affects that 
condition repeatedly until that condition becomes f al se. At that point, the loop exits, and script exe- 
cution continues with statements after the closing brace. If the statements inside the whi I e loop do 
not somehow affect the values being tested in condi ti on, your script never exits, and it becomes 
stuck in an infinite loop. 

Many loops can be rendered with either the for or while loops. In fact, Listing 21-4 shows awhile 
loop version of the for loop from Listing 21-3. 



LISTING 21-4 



A while Loop Version of Listing 21-3 

JavaScript: jsb-2104. js 

function showMegapi xel s ( ) 
{ 

var theForm = document . getEl ementBy Id (' si zes Form ') ; 
if (theForm) 
{ 

var sizeChoices = theForm. choi ces ; 
var i = 0 ; 

while (i < si zeChoi ces . I ength && ! si zeChoi ces [ i ]. checked ) 
I 

i++; 



alert("That image size requires " + si zeChoi ces [ i ]. val ue + 
" mega pi xel s . " ) ; 

) 

} 



One point you may notice is that if the condition of a while loop depends on the value of a loop 
counter, the scripter is responsible for initializing the counter prior to the while loop construction 
and managing its value within the whi I e loop. 

Should you need their powers, the break and continue control statements work inside while 
loops just as they do in for loops. But because the two loop styles treat their loop counters and 
conditions differently, be extra careful (do lots of testing) when applying break and conti nue 
statements to both kinds of loops. 



389 



Part III: JavaScript Core Language Reference 



do-while 

No hard-and-fast rules exist for which type of loop construction to use in a script. Generally, use 
whi 1 e loops only when the data, or object, to loop through is already part of the script before the 
loop. In other words, by virtue of previous statements in the script, the values for any condition or 
loop counting (if needed) are already initialized. But if cycling through an object's properties, or an 
array's entries, to extract some piece of data for use later in the script is what's needed, favor the for 
loop. The for loop is also generally preferred when the looping involves a simple counter from one 
value to another. 

Another point of style, particularly with the for loop, is where a scripter should declare the i vari- 
able. Some programmers prefer to declare (or initialize, if initial values are known) all variables in the 
opening statements of a script or function. That is why you tend to see a lot of v a r statements in 
those positions in scripts. If you have only one for loop in a function, for example, nothing is wrong 
with declaring and initializing the i loop counter in the initial expression part of the for loop (as 
demonstrated frequently in the previous sections). But if your function utilizes multiple for loops 
that reuse the i counter variable (that is, the loops run completely independently of one another), 
then you can declare the i variable once at the start of the function and simply assign a new initial 
value to i in each for construction. 

The do-while Loop 

Compatibility: WinIE4+, MacIE4+, NN4+, Moz-I-, Safari 4-, Opera4-, Chrome4- 

JavaScript brings you one more looping construction, called the do-whi 1 e loop. The formal syntax 
for this construction is as follows: 

do 

{ 

statements 
} while (condition) 

An important difference distinguishes the do-whi 1 e loop from the while loop. In the do-while 
loop, the statements in the construction always execute at least one time before the condition can 
be tested; in a whi 1 e loop, the statements may never execute if the condition tested at the outset 
evaluates to false. So, just think of the do-while loop as a while loop where the statements get 
executed at least once, no matter what. 

Use a d o - w h i 1 e loop when you know for certain that the looped statements are free to run at least 
one time. If the condition may not be met the first time, use the whi 1 e loop. For many instances, 
the two constructions are interchangeable, although only the while loop is compatible with legacy 
browsers. 

Looping through Properties (for-in) 

Compatibility: WinIE34-, MacIE34-, NN24-, Moz4-, Safari 4-, Opera4-, Chrome 4- 

JavaScript includes a variation of the for loop, called a f or-i n loop, which has special powers of 
extracting the names and values of any object property currently in the browser's memory. The syntax 
looks like this: 

for [varName in object) 

{ 



390 



Chapter 21 : Control Structures and Exception Handling 



for-in 

// statements 

) 

The object parameter is not the string name of an object but a reference to the object itself. 
JavaScript delivers an object reference if you provide the name of the object as an unquoted string, 
such as wi ndow or document, or via getEl ementBy Id . Recall that although a legal name 
in HTML is case-insensitive, a legal name in JavaScript is case-sensitive, so remember to use the 
camelCase convention even in your HTML code. Using the varNatne variable, you can create a script 
that extracts and displays the range of properties for any given object. 

Listings 21-5 shows a page containing a utility function that you can insert into your external 
JavaScript files during the authoring and debugging stages of designing a JavaScript-enhanced page. 
In the example, the current wi ndow object is examined, and its properties are presented in the page 
(note that Safari 1.0 doesn't expose wi ndow object properties). 



LISTING 21-5 



Property Inspector Function 

HTML: jsb-21-05.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Property Inspector Functi on</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb-21 -05 . j s "></scri pt> 
<link rel ="styl esheet" href="jsb-21-05.css" type="text/css"> 

</head> 

<body> 

<hl>Property Inspector Functi on</hl> 
<p>Here are the properties of the current window:</p> 
<ul i d="property Li st "></ul > 
</body> 
</html > 

JavaScript: jsb-21-05.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', showProps); 

// display all the properties of the object 

functi on showProps ( ) 

{ 

var oOutput = document . getEl ementBy Id( ' property Li st ') ; 
if (oOutput) 
{ 

var newElem; 
var newText; 
for (var i in window) 

continued 



391 



Part III: JavaScript Core Language Reference 



with 



LISTING 21-5 



(continued) 



newElem = document . createEl ement (' 1 i ') ; 

newEl em . cl assName = ' obj Property ' ; 

newText = document . createTextNode (' wi ndow . ' + i + ' 

// insert the text node into the new paragraph 
newElem.appendChild( newText ) ; 

// insert the completed paragraph into propertyList 
oOutput . appendChi 1 d ( new El em) ; 



+ wi ndow[ i ] ) 



Stylesheet: jsb-2105.css 

ul#propertyLi st 1 i 
{ 

white-space: pre; 

) 



For debugging purposes, you can revise the function slightly to display the results in an alert dia- 
log box or a textarea element. Just use the \n carriage return character after each property for a 
nicely formatted display. If the showProps ( ) function looks familiar to you, it is because it closely 
resembles the property inspector routines of The Evaluator (see Chapter 4). In Chapter 48 (on the 
CD-ROM), you can see how to embed functionality of The Evaluator into a page under construction 
so that you can view property values while debugging your scripts. 



The with Statement 



Compatibility: WmIE34-, MacIE34-, NN24-, Moz4-, Safari 4-, Opera4-, Chrome 4- 

The with statement enables you to preface any number of statements by advising JavaScript on 
precisely which object your scripts will be talking about, so that you don't have to use full, formal 
addresses to access properties or invoke methods of the same object. The formal syntax definition of 
the with statement is as follows: 

with (object) 

{ 

statements 

} 

The object reference is a reference to any valid object currently in the browser's memory. An example 
of this appears in Chapter 16, "The Math, Number, and Boolean Objects," when the Math object is 
discussed. By embracing several Math statements inside a with construction, your scripts can call the 



392 



Chapter 21 : Control Structures and Exception Handling 



properties and methods without having to make the object part of every reference to those properties 
and methods. Here's an example: 

with (Math) 
{ 

var randlnt = round( random( ) * 100); 

) 

This example uses the round ( ) and random ( ) methods of the Math object to obtain a random 
integer between 0 and 100. The significance of the code is how the with statement allows you to 
forego using the full notation ofMath.roundO and Math.randomO. 

An advantage of the with structure is that it can make heavily object-dependent statements easier to 
read and understand. Consider this long version of a function that requires multiple calls to the same 
object (but different properties): 

function seeColor(form) 

var newColor = ( form. col ors Li st . opt i ons [form. col orsLi st . sel ectedlndex] 
.text) ; 

return newColor; 

) 

Using the with structure, you can shorten the long statement: 

function seeCol or(form) 
{ 

with ( f orm . col ors Li st ) 
{ 

newColor = ( opti ons [ sel ected I ndex] . text ) ; 

} 

return newColor; 

} 

When JavaScript encounters an otherwise unknown identifier inside a wi th statement, it tries to build 
a reference out of the object specified as its parameter and that unknown identifier. You cannot, how- 
ever, nest with statements that build on one another. For instance, in the preceding example, you 
cannot have a wi th (col ors Li st) nested inside a with (form) statement and expect JavaScript to 
create a reference to options out of the two object names. 

As clever as the with statement may seem, be aware that there are some cautions associated with 
its use. It introduces some inherent performance penalties in your script (because of the way the 
JavaScript interpreter must artificially generate references). You probably won't notice degradation with 
occasional use of this construction, but if it's used inside a loop that must iterate many times, process- 
ing speed will almost certainly be affected negatively. Additionally, some people feel that the with 
statement introduces ambiguity in your code. 

Labeled Statements 



Compatibility: WmIE4+, MacIE4+, NN4+, Moz4-, Safari-!-, Opera4-, Chrome 4- 

Craftmg multiple nested loops can sometimes be difficult when the final condition your script is look- 
ing for is met deep inside the nests. The problem is that the break or continue statement by itself 



393 



Part III: JavaScript Core Language Reference 



has scope only to the nearest loop level. Therefore, even if you break out of the inner loop, the outer 
loop(s) continue to execute. If all you want to do is exit the function after the condition is met, a sim- 
ple return statement performs the same job as some other languages' exit command. But if you also 
need some further processing within that function after the condition is met, you need the JavaScript 
facility supported in modern browsers that lets you assign labels to blocks of statements. Your break 
and continue statements can then alter their scope to apply to a labeled block other than the one 
containing the statement. 

A label is any identifier (that is, a name starting with a letter and containing no spaces or odd punc- 
tuation other than underscores) followed by a colon preceding a logical block of executing statements, 
such as an if. . .then or loop construction. The formal syntax looks like the following: 

label ID: 

statements 

For a break or continue statement to apply itself to a labeled group, the label is added as a kind 
of parameter to each statement, as in 

break labellD; 
continue labellD; 



Note 

If you're arriving at JavaScript from another programming language that has a bit more structure, such as C++ 
or Java, the thought of labeled code may have you worried about the risks of creating code that is impossible to 
manage. This worry is likely rooted in the goto statement that is found in some languages, such as BASIC, and 
which is seriously frowned upon in modern structured languages. Labels in JavaScript are much more limited 
than the infamous goto statement in other languages; you can only use the break statement to target a label 
in which your code is nested. So, although we don't necessarily encourage the heavy usage of labels, you can 
rest easy knowing that they aren't on par with the much maligned goto statement. ■ 



To demonstrate how valuable labels can be in the right situation, Listing 21-6 contains two versions 
of the same nested loop construction. The goal of each version is to loop through two different index 
variables until both values equal the target values set outside the loop. When those targets are met, 
the entire nested loop construction should break off and continue processing afterward. To help you 
visualize the processing that goes on during the execution of the loops, the scripts output intermediate 
and final results to a textarea. 

In the version without labels, only the simple break statement is issued when the targets are met. 
This breaks the inner loop at that point, but the outer loop picks up on the next iteration. By the time 
the entire construction has ended, a lot of wasted processing has gone on. Moreover, the values of the 
counting variables max themselves out, because the loops execute in their entirety several times after 
the targets are met. 

But in the labeled version, the inner loop breaks out of the labeled outer loop as soon as the tar- 
gets are met. Far fewer lines of code are executed, and the loop counting variables are equal to the 
targets, as desired. Experiment with Listing 21-6 by changing the break statements to conti nue 
statements. Then closely analyze the two results in the Results textarea to see how the two versions 
behave. 



394 



Chapter 21 : Control Structures and Exception Handling 



LISTING 21-6 



Labeled Statements 

HTML: jsb-21-06.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Breaki ng Out of Nested Labeled Loops</ti tl e> 
<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb-21 -06 . j s "></scri pt> 

</head> 

<body> 

<hl>Breaking Out of Nested Labeled Loops</hl> 

<p>Look in the Results field for traces of these button scripts:</p> 
<form i d="theForm" acti on = "val i date . php" method="get"> 

<p><input i d="wi thoutLabel Button" type="button" val ue="Execute WITHOUT*-^ 
Label "></p> 

<p><input i d="wi th Label Button " type="button" val ue="Execute WITH<J 
Label "></p> 

<P> 

< 1 a be 1 for=" output") Re sults:</label> 

<textarea id="output" rows="43" col s="60"X/textarea> 

</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-2106.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// locate output field 

out = document . getEl ementBy Id (' output ') ; 

// if found . . . 

i f ( out ) 

{ 

// add an event to the button button labeled Execute WITHOUT Label 

add Even t ( document .getEl ementBy Id ( 'withoutLabelButton'), 'click', runl); 

// add an event to the button button labeled Execute WITH Label 
addEvent ( document .getEl ementBy Id ( 'withLabelButton'), 'click', run2); 

1 

continued 



395 



Part III: JavaScript Core Language Reference 



LISTING 21-6 



(continued) 



var out; // global variable for output field 

var targetA = 2; 

var targetB = 2; 

var range = 5; 

f uncti on runl ( ) 
{ 

out. value = "Running WITHOUT labeled break\n"; 

for (var i = 0; i <= range; i++) 

{ 

out. value += "Outer loop #" + i + "\n"; 

for (var j = 0; j <= range; 

{ 

out. value += " Inner loop #" + j + "\n"; 

if (i == targetA && j == targetB) 

{ 

out. value += "**BREAKI NG OUT OF INNER L00P**\n' 
break; 



out. value += "After looping, i = " + i + " , j = " + j + "\n' 

} 

f uncti on run2( ) 
{ 

out. value = "Running WITH labeled break\n"; 
outerLoop : 

for (var i = 0; i <= range; i++) 
{ 

out. value += "Outer loop #" + i + "\n"; 
i nnerLoop : 

for (var j = 0; j <= range; 
{ 

out. value += " Inner loop #" + j + "\n"; 

if (i == targetA && j == targetB) 

{ 

out. value += "**BREAKI NG OUT OF OUTER L00P**\n"; 
break outerLoop; 



out. value += "After looping, i = " + i + " , j = " + j + "\n' 



396 



Chapter 21 : Control Structures and Exception Handling 



Exception Handling 

The subject of exception handling is relatively new to JavaScript. Formalized in Edition 3 of 
ECMA-262, parts of the official mechanism were implemented in IE5, with more complete implemen- 
tations in IE6 and NN6, and, of course, in Mozilla, Firefox, Camino, Safari, Opera, and Chrome. 

Exceptions and errors 

If you've done any scripting, you are certainly aware of JavaScript errors, whether they be from syn- 
tax errors in your code, or what are known as runtime errors — errors that occur while scripts are 
processing information. Ideally, a program should be aware of when an error occurs and handle it as 
gracefully as possible. This self-healing can prevent lost data and help keep users from seeing ugly 
error messages. Chapter 27, "Window and Frame Objects," covers the onerror event handler and 
wi ndow . onerror property, which were early attempts at letting scripts gain a level of control over 
runtime errors. This event-driven mechanism works on a global level (that is, in the wi ndow object) 
and processes every error that occurs throughout the page. This event handler ends up being used pri- 
marily as a last-ditch defense against displaying any error message to the user, and is a long way from 
what programmers consider to be proper exception handling. 

In the English language, the term "exception" can mean something out of the ordinary, or something 
abnormal. This definition seems quite distant from the word "error," which usually means a mistake. 
In the realm of programming languages, however, the two words tend to be used interchangeably, and 
the difference between the two depends primarily on one's point of view. 

Consider, for example, a simple script whose job is to multiply numbers that the user enters into two 
text fields on the page. The script is supposed to display the results in a third text box. If the script 
contains no data entry validation, JavaScript will attempt to multiply whatever values are entered 
into the text boxes. If the user enters two numbers, JavaScript is smart enough to recognize that even 
though the value properties of the two input text fields are strings, the strings contain numbers that 
can be converted to number types for the proper multiplication. Without complaint, the product of 
the two numbers gets calculated and displayed into the results. 

But what if the user types a letter into one of the text boxes? Again, without any entry validation in 
the script, JavaScript has a fixed way of responding to such a request: The result of the multiplication 
operation is the N a N (not a number) constant. If you are an untrained user, you have no idea what 
N a N means, but your experience with computers tells you that some kind of error has occurred. You 
may blame the computer or you may blame yourself — the accurate response may in fact be to blame 
the JavaScript developer! 

To shift the point of view to the programmer, however, the script was designed to be run by a user 
who never makes a typing mistake, intentional or not. That, of course, is not very good programming 
practice. Users make mistakes. Therefore, anticipating user input that is not what would be expected 
is the programmer's job — input that is an exception to the rules your program wants to operate by. 
You must include some additional code that handles the exceptions gracefully so as to not confuse 
the user with unintelligible output, and perhaps even to help the user repair the input to get a result. 
This extra programming code handles the undesirable and erroneous input and makes your scripts 
considerably more user-friendly and robust. 

As it turns out, JavaScript and the W3C Document Object Model liberally mix terms of exception and 
error within the vocabulary used to handle exceptions. As you see shortly, an exception creates an 



397 



Part III: JavaScript Core Language Reference 



try-catch-finally 

error object, which contains information about the exception. It is safe to say that you can think of 
exceptions and errors as the same things. 

The exception mechanism 

Newcomers to JavaScript (or any programming environment, for that matter) may at first have a 
difficult time creating a mental model of how all this exception stuff runs within the context of the 
browser. It may be easy enough to understand how pages load and create object models, and how 
event handlers (or listeners, in the W3C DOM terminology) cause script functions to run. But a lot of 
action also seems to be going on in the background. For example, the event object that is generated 
automatically with each event action (see Chapter 32, "Event Objects") seems to sit "somewhere," 
while event handler functions run so that they can retrieve details about the event. After the functions 
finish their processing, the event object disappears, without even leaving behind a Cheshire Cat smile. 
Mysterious. 

Browsers equipped for exception handling have more of this "stuff running in the background, 
ready for your scripts when you need it. Because you have certainly viewed the details of at least one 
scripting error, you have already seen some of the exception-handling mechanism that is built into 
browsers. If a script error occurs, the browser creates in its memory an error object, whose properties 
contain details about the error. The precise details (described later in this chapter) vary from one 
browser brand to the next, but what you see in the error details readout is the default way the 
browser handles exceptions/errors. As browsers have matured, their makers have gone to great lengths 
to tone down the intrusion of script errors. For example, in NN4+, errors appeared in a separate 
JavaScript Console window (which must be invoked in NN4 by typing javascript: into the 
Location field; or opened directly via the Tools menu in NN6+ and Mozilla-based browsers, including 
Firefox and Camino). In IE4+ for Windows, the status bar comes into play again, as the icon at the 
bottom-left comer turns into an alert icon: Double-clicking the icon displays more information about 
the error. MacIE users can turn off scripting error alerts altogether. Safari 1.0 didn't divulge any script 
errors but a JavaScript console was added as of version 1.3. 

True exception handling, however, goes further than just displaying error messages. It also provides 
a uniform way to let scripts guard against unusual occurrences. Ideally, the mechanism makes sure 
that all runtime errors get funneled through the same mechanism to help simplify the scripting of 
exception handling. The mechanism is also designed to be used intentionally as a way for your own 
code to generate errors in a uniform way so that other parts of your scripts can handle them quietly 
and intelligently. In other words, you can use the exception handling mechanism as a kind of "back 
channel" to communicate from one part of your scripts to another. 

The JavaScript exception handling mechanism is built around two groups of program execution state- 
ments. The first group consists of the try-catch-f i nal ly statement triumvirate; the second group 
is the single throw statement. 

Using try-catch-finally Constructions 

The purpose of the try-catch-finally group of related statements is to provide a controlled envi- 
ronment in which script statements that may encounter runtime errors can run, such that your scripts 
can act upon exceptions without alarming the rest of the browser's error mechanisms. Each of the 
three statements precedes a block of code in the following syntax: 

try 

{ 

statements to run 



398 



Chapter 21 : Control Structures and Exception Handling 



try-catch-finally 



catch (errorlnfo) 

statements to run if exception occurs in try block 
finally 

statements to run whether or not an exception occurred [opti onal ] 

Each try block must be mated with a catch and/or final I y block at the same nesting level, with 
no intervening statements. For example, a function can have a one-level try-catch construction 
inside it as follows: 

function my F un c ( ) 
{ 

try 
{ 

// statements 

I 

catch (e) 
{ 

// statements 

} 

} 

But if there were another try block nested one level deeper, a balancing catch or finally block 
would also have to be present at that deeper level: 

function myFuncO 
{ 

try 
{ 

// statements 

try 

{ 

// statements 

} 

catch (e) 
{ 

// statements 

I 

I 

catch (e) 
{ 

// statements 

} 

} 

The statements inside the t ry block include statements that you believe are capable of generating a 
runtime error because of user input errors, the failure of some page component to load, or a similar 

399 



Part III: JavaScript Core Language Reference 



try-catch-finally 

error. The presence of the catch block prevents errors from appearing in the browser's regular 
script error reporting system (for example, the JavaScript Console of Safaril.3+, NN6+, and 
Mozilla -based browsers). 

An important term to know about exception handling of this type is throw. The convention is that 
when an operation or method call triggers an exception, it is said to "throw an exception." For 
example, if a script statement attempts to invoke a method of a string object, but that method does 
not exist for the object (perhaps you mistyped the method name), JavaScript throws an exception. 
Exceptions have names associated with them — a name that sometimes, but not always, reveals 
important information about the exception. In the mistyped method example just cited, the name 
of that exception is a TypeError (yet more evidence of how "exception" and "error" become 
intertwined) . 

The JavaScript language supported in modern browsers is not the only entity that can throw excep- 
tions. The W3C DOM also defines categories of exceptions for DOM objects. For example, according 
to the Level 2 specification, the appendChi 1 d( ) method (see Chapter 26, "Generic HTML Element 
Objects") can throw (or raise, in the W3C terminology) one of three exceptions: 



Exception Name 


When Thrown 


H I ERARCHY_REQUEST_ERR 


If the current node is of a type that does not allow 
children of the type of the newChi 1 d node, or if the 
node to append is one of this node's ancestors 


WRONG_DOCUMENT_ERR 


If newChi 1 d was created from a different document than 
the one that created the current node 


N0_M0DI FICATION_ALLOWED_ERR 


If the current node is read-only 



Because the appendChi 1 d( ) method is capable of throwing exceptions, a JavaScript statement that 
invokes this method should ideally be inside a try block. If an exception is thrown, then script exe- 
cution immediately jumps to the catch or finally block associated with the try block. Execution 
does not come back to the try block. 

A catch block has special behavior. Its format looks similar to a function in a way, because the 
catch keyword is followed by a pair of parentheses and an arbitrary variable that is assigned a ref- 
erence to the error object whose properties are filled by the browser when the exception occurs. One 
of the properties of that error object is the name of the error. Therefore, the code inside the catch 
block can examine the name of the error and perhaps include some branching code to take care of a 
variety of different errors that are caught. 

To see how this construction may appear in code, look at a hypothetical generic function whose job 
is to create a new element and append it to some other node. Both the type of element to be created 
and a reference to the parent node are passed as parameters. To take care of potential misuses of this 
function through the passage of improper parameter values, it includes extra error handling to treat all 
possible exceptions from the two DOM methods: createEl ement( ) and appendChi 1 d( ). Such a 
function looks like Listing 21-7. 



400 



Chapter 21 : Control Structures and Exception Handling 



try-catch-finally 



LISTING 21-7 



A Hypothetical try-catch Routine 

// generic appender 

function attachToEnd ( theNode , newTag) 

{ 

try 
{ 

var newElem = document . createEl ement( newTag ) ; 
theNode. appendChild(new El em); 

} 

catch (e) 
{ 

switch (e.name) 
{ 

case " I NVALI D_CHARACTER_ERR" : 

// statements to handle this createEl ement( ) error 
break; 

case "HI ERARCHY_REQUEST_ERR" : 

// statements to handle this appendChi 1 d( ) error 
break; 

case "WRONG_DOCUMENT_ERR" : 

// statements to handle this appendChi 1 d( ) error 
break; 

case "N0_M0DI FICATION_ALLOWED_ERR" : 

// statements to handle this appendChi 1 d( ) error 
break; 

def aul t : 

// statements to handle any other error 

} 

return false; 

} 

return true; 

1 



The single catch block in Listing 21-7 executes only if one of the statements in the try block 
throws an exception. The exceptions may be not only one of the four specific ones named in the 
catch block, but also syntax or other errors that could occur inside the try block. That's why you 
have a last-ditch case to handle truly unexpected errors. Your job as scripter is to anticipate errors 
and provide clean ways for the exceptions to be handled, whether it be through judiciously worded 
alert dialog boxes or through self-repair. For example, in the case of the invalid character error for 
createEl ement( ), your script may attempt to salvage the data passed to the attachToEnd( ) 
function and remvoke the method, passing theNode value as-is and the repaired value originally 
passed to newTag. If your repairs were successful, the try block would execute without error and 
carry on with the user's being completely unaware that a nasty problem had been averted. And that's 
really the goal of exception handling — to save the day when something "unexpected" goes wrong so 
that the user isn't left confused or frustrated. 



401 



Part III: JavaScript Core Language Reference 



throw 

A finally block contains code that always executes after a t ry block, whether or not the try block 
succeeds without throwing an error. Unlike the catch block, a finally block does not receive an 
error object as a parameter, so it operates very much in the dark about what transpires inside the try 
block. If you include both catch and finally blocks after a try block, the execution path depends 
on whether an exception is thrown. If no exception is thrown, the final 1 y block executes after the 
last statement of the try block runs. But if the try block throws an exception, program execution 
runs first to the catch block. After all processing within the catch block finishes, the finally 
block executes. In development environments that give programmers complete control over resources, 
such as memory allocation, a finally block may be used to delete some temporary items generated 
in the t ry block, whether or not an exception occurs in the t ry block. Currently, JavaScript's auto- 
matic memory management system reduces the need for that kind of maintenance, but you should 
be aware of the program execution possibilities of the finally block in the try-catch-finally 
context. 

Real-life exceptions 

The example shown in Listing 21-7 is a bit idealized. The listing assumes that the browser dutifully 
reports every W3C DOM exception precisely as defined in the formal specification. Unfortunately, 
even the latest browsers have yet to fully comply with the DOM when it comes to exception report- 
ing. Most browsers implement additional error naming conventions and layers between actual DOM 
exceptions and what gets reported with the error object at the time of the exception. 

If you think these discrepancies make cross-browser exception handling difficult, you're right. Even 
simple errors are reported differently among the two major browser brands (IE and Mozilla) and the 
W3C DOM specification. Until the browsers exhibit a greater unanimity in exception reporting, the 
smoothest development road will be for those scripters who have the luxury of writing for just one of 
the browser platforms, such as IE for Windows or Safari for Mac. 

That said, however, one aspect of exception handling can still be used in all modern browsers with- 
out a hitch. You can take advantage of try-catch constructions to throw your own exceptions — a 
practice that is quite common in advanced programming environments. 

Throwing Exceptions 

The last exception handling keyword not yet covered — throw — makes it possible to utilize 
exception-handling facilities for your own management of processes, such as data entry validation. 
At any point inside a t ry block, you can manually throw an exception that gets picked up by the 
associated catch block. The details of the specific exception are up to you. 

Syntax for the throw statement is as follows: 
throw value; 

The value you throw can be of any type, but good practice suggests that the value be an error object 
(described more fully later in this chapter). Whatever value you throw is assigned to the parameter of 
the catch block. Look at the following two examples. In the first, the value is a string message; in 
the second, the value is an error object. 

Listing 21-8 presents one input text box for a number between 1 and 5. Clicking a button looks up 
a corresponding letter in an array and displays the letter in a second text box. The lookup script has 
two simple data validation routines to make sure the entry is a number and is in the desired range. 



402 



Chapter 21 : Control Structures and Exception Handling 



throw 

Error checking here is done manually by script. If either of the error conditions occurs, throw state- 
ments force execution to jump to the catch block. The catch block assigns the incoming string 
parameter to the variable e. The design here assumes that the message being passed is text for an alert 
dialog box. Not only does a single catch block take care of both error conditions (and conceivably 
any others to be added later), but the catch block runs within the same variable scope as the func- 
tion, so that it can use the reference to the input text box to focus and select the input text if there is 
an error. 



LISTING 21-8 



Throwing String Exceptions 

HTML: jsb-21-08.html 

<!D0CTYPE html> 
<html > 
<head> 

<meta http-equi v="content-type" content="text/html ; charset=utf -8"> 
<ti tl e>Throwi ng a String Excepti on</ti tl e> 

<script type=" text /javascript" src="../jsb-global .js"X/script> 
<script type="text/ j avascri pt" src=" j sb-21 -08 . j s "></scri pt> 

</head> 

<body> 

<hl>Throwing a String Excepti on</hl> 

<form id="theForm" acti on = "val i date . php" method="get"> 

<P> 

< 1 a be 1 f or=" vi si tor I nput ">Enter a number from 1 to 5 : < / 1 a be 1 > 
<input type="text" i d=" vi si tor I nput " size="5"> 
<input type="button" id="getLetterButton" value="Get Letter") 
< 1 a be 1 f or="output">Matchi ng Letter i s : < / 1 a be 1 > 
<input type="text" id="output" size="5"> 
</p> 
</ f orm> 
</body> 
</html > 

JavaScript: jsb-2108. js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// add an event to the Get Letter button 

add E ven t ( document . get El erne nt By Id ( 'getLetterButton'), 'click', get Letter); 

} 

var letters = new Array ( "A" , "B" , "C" , "D" , "E" ) ; 
functi on getLetter( ) 

continued 



403 



Part III: JavaScript Core Language Reference 



throw 



LISTING 21-8 



(continued) 



try 
{ 

var inputField = document . getEl ementBy Id (' vi si tor I nput ') ; 

var inp = parsel nt ( i nput Fi el d . val ue , 10); 

var outputField = document . getEl ementBy Id (' output ') ; 

if (isNaN(inp)) 
{ 

throw "Entry was not a number."; 

} 

if (inp < 1 || inp > 5) 
{ 

throw "Enter only 1 through 5."; 

1 



outputFi el d . val ue = letters[inp - 1]; 

} 

catch (e) 
{ 

al ert(e) ; 

outputFi el d . val ue = ""; 
i nputFi eld. f ocus ( ) ; 
i nputFi el d . sel ect{ ) ; 

) 



The flaw with Listing 21-8 is that if some other kind of exception were thrown inside the try block, 
the value passed to the catch block would be an error object, not a string. The alert dialog box dis- 
played to the user would be meaningless. Therefore, it is better to be uniform in your throw-catch 
constructions and pass an error object. 

Listing 21-9 is an updated version of Listing 21-8, demonstrating how to create an error object 
that gets sent to the catch block via throw statements. The HTML code is exactly the same as for 
listing 21-8, so that is not repeated here. 



LISTING 21-9 



Throwing an Error Object Exception 

JavaScript: jsb-2109.js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// add an event to the Get Letter button 



404 



Chapter 21 : Control Structures and Exception Handling 



throw 

add Event ( document . get El erne nt By Id ( 'getLetterButton'), 'click', get Letter); 

} 

var letters = new Array ( "A" , "B" , "C" , "D" , "E" ) ; 

function getErrorObj (msg) 
{ 

var err = new Error(msg); 
return err; 

} 

functi on getLetter( ) 
{ 

try 
{ 

var inputField = document . getEl ementBy Id (' vi si tor I nput ') ; 

var inp = parsel nt ( i nput Fi el d . val ue , 10); 

var outputField = document . getEl ementBy Id (' output ') ; 

if (isNaN(inp)) 
{ 

throw getErrorObj (" Entry was not a number."); 

} 

if (inp < 1 || inp > 5) 
{ 

throw getErrorObj (" Enter only 1 through 5."); 

} 

outputFi el d . val ue = letters[inp - 1]; 

) 

catch (e) 
{ 

al ert ( e . message ) ; 
outputFi el d . val ue = ""; 
i nputFi eld. f ocus ( ) ; 
i nputFi el d . sel ect( ) ; 



The only difference to the catch block is that it now reads the message property of the incom- 
ing error object. This means that if some other exception is thrown inside the try block, the 
browser-generated message will be displayed in the alert dialog box. 

In truth, however, the job really isn't complete. In all likelihood, if a browser-generated exception is 
thrown, the message in the alert dialog box won't mean much to the user. The error message will 
probably be some kind of syntax or type error — the kind of meaningless error message you often 
get from your favorite operating system. A better design is to branch the catch block so that while 
"intentional" exceptions thrown by your code are handled through the alert dialog box messages 
you've put there, other types are treated differently. To accomplish this, you can take over one of 
the other properties of the error object — name — so that your catch block treats your custom 
messages separately. 



405 



Part III: JavaScript Core Language Reference 



throw 

In Listing 21-10, the getErrorObj ( ) function adds a custom value to the name property of the 
newly created error object. The name you assign can be any name, but you want to avoid excep- 
tion names used by JavaScript or the DOM. Even if you don't know what all of those are, you can 
probably conjure up a suitably unique name for your error. Down in the catch block, a switch 
construction branches to treat the two classes of errors differently. In this simplified example, about 
the only possible problem other than the ones being trapped for explicitly in the try block would 
be some corruption to the page during downloading. Therefore, for this example, the branch for all 
other errors simply asks that the user reload the page and try again. The point is, however, that you 
can have as many classifications of custom and system errors as you want and handle them in a single 
catch block accordingly. Again, the HTML code is exactly the same as for listing 21-8, so it is not 
repeated here. 



LISTING 21-10 



A Custom Object Exception 

JavaScript: jsb-2110. js 

// initialize when the page has loaded 
addEvent(wi ndow, 'load', initialize); 

f uncti on i ni ti al i ze ( ) 
{ 

// add an event to the Get Letter button 

add E ven t ( document . get El erne nt By Id ( 'getLetterButton'), 'click', get Letter); 

} 

var letters = new Array ( "A" , "B" , "C" , "D" , "E" ) ; 

function getErrorObj (msg) 
{ 

var err = new Error(msg); 
err. name = "MY_ERR0R" ; 
return err; 



functi on getLetter( ) 
{ 

try 
{ 

var inputField = document . getEl ementBy Id (' vi si tor I nput ') ; 

var inp = parsel nt ( i nput Fi el d . val ue , 10); 

var outputField = document . getEl ementBy Id (' output ') ; 

if (isNaN(inp)) 
{ 

throw getErrorObj (" Entry was not a number."); 

} 

if (inp < 1 || inp > 5) 
{ 

throw getErrorObj (" Enter only 1 through 5."); 



406 



Chapter 21 : Control Structures and Exception Handling 



errorObject 

} 

outputFi el d . val ue = letters[inp - 1]; 

} 

catch (e) 
{ 

switch (e.name) 
{ 

case ' MY_ERR0R ' : 
al ert ( e . message ) ; 
outputFi el d . val ue = ""; 
i nputFi el d . focus ( ) ; 
i nputFi el d . sel ect ( ) ; 
break; 

default : 

al ert( ' Rel oad the page and try again.'); 



If you want to see how the alternative branch of Listing 21-10 looks, copy the listing file from the 
CD-ROM to your hard disk and modify the last line of the try block so that one of the characters is 
dropped from the name of the array: 

outputFi eld. value = letterfinp - 1]; 

This may simulate the faulty loading of the page. If you enter one of the allowable values, the reload 
alert appears, rather than the actual message of the error object: letter is undefined. Your users will 
thank you. 

All that's left now on this subject are the details of the error object. 

Error Object 

Properties Methods 

errorObject . prototype errorObject. toStringO 

errorObject . constructor 

errorObject . descri pti on 

errorObject . f i 1 ename 

errorObject . 1 i neN umber 

errorObject . message 

errorObject . name 

errorObject . number 



407 



Part III: JavaScript Core Language Reference 



errorOfe/eef.constructor 

Syntax 

Creating an error object: 

var myError = new Error( "message" ) ; 
var myError = Error ( "message" ) ; 

Accessing static Error object property: 

Error . property 

Accessing error object properties and methods: 

errorObject . property | method(Lparametersl) 
Compatibility: WinIE5+, MacIE-, NN6+, Moz+, Safan+, Opera+, Chrome+ 

About this object 

An error object instance is created whenever an exception is thrown or when you invoke either of 
the constructor formats for creating an error object. Properties of the error object instance contain 
information about the nature of the error so that catch blocks can inspect the error and process error 
handling accordingly. 

IE5 implemented an error object in advance of the ECMA-262 formal error object, and the IE5 version 
ended up having its own set of properties that are not part of the ECMA standard. Those propri- 
etary properties are still part of IE5.5+, which includes the ECMA properties as well. NN6, on the 
other hand, started with the ECMA properties and adds two proprietary properties of its own. The 
browser uses these additional properties in its own script error reporting. The unfortunate bottom line 
for cross-browser developers is that no properties in common among all browsers support the error 
object. However, there are two common denominators (name and message) between IE5.5+ and 
other browsers. 

As described earlier in this chapter, you are encouraged to create an erro